SickGaming Rust Server Plugins

This commit is contained in:
Aaron 2021-02-11 21:10:50 +00:00
commit b76e392940
49 changed files with 36770 additions and 0 deletions

57
config/BetterLoot.json Normal file
View File

@ -0,0 +1,57 @@
{
"Generic": {
"blueprintProbability": 0.11,
"listUpdatesOnLoaded": true,
"removeStackedContainers": true,
"WatchedPrefabs": [
"assets/bundled/prefabs/radtown/crate_basic.prefab",
"assets/bundled/prefabs/radtown/crate_elite.prefab",
"assets/bundled/prefabs/radtown/crate_mine.prefab",
"assets/bundled/prefabs/radtown/crate_normal.prefab",
"assets/bundled/prefabs/radtown/crate_normal_2.prefab",
"assets/bundled/prefabs/radtown/crate_normal_2_food.prefab",
"assets/bundled/prefabs/radtown/crate_normal_2_medical.prefab",
"assets/bundled/prefabs/radtown/crate_tools.prefab",
"assets/bundled/prefabs/radtown/crate_underwater_advanced.prefab",
"assets/bundled/prefabs/radtown/crate_underwater_basic.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm ammo.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm c4.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm construction resources.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm construction tools.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm food.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm medical.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm res.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm tier1 lootbox.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm tier2 lootbox.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm tier3 lootbox.prefab",
"assets/bundled/prefabs/radtown/vehicle_parts.prefab",
"assets/bundled/prefabs/radtown/foodbox.prefab",
"assets/bundled/prefabs/radtown/loot_barrel_1.prefab",
"assets/bundled/prefabs/radtown/loot_barrel_2.prefab",
"assets/bundled/prefabs/autospawn/resource/loot/loot-barrel-1.prefab",
"assets/bundled/prefabs/autospawn/resource/loot/loot-barrel-2.prefab",
"assets/bundled/prefabs/autospawn/resource/loot/trash-pile-1.prefab",
"assets/bundled/prefabs/radtown/loot_trash.prefab",
"assets/bundled/prefabs/radtown/minecart.prefab",
"assets/bundled/prefabs/radtown/oil_barrel.prefab",
"assets/prefabs/npc/m2bradley/bradley_crate.prefab",
"assets/prefabs/npc/patrol helicopter/heli_crate.prefab",
"assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab",
"assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate_oilrig.prefab",
"assets/prefabs/misc/supply drop/supply_drop.prefab"
]
},
"Loot": {
"enableHammerLootCycle": false,
"hammerLootCycleTime": 3,
"lootMultiplier": 1,
"scrapMultiplier": 1
},
"Rarity": {
"Override": {
"autoturret": 4,
"lmg.m249": 4,
"targeting.computer": 3
}
}
}

File diff suppressed because it is too large Load Diff

51
config/GatherManager.json Normal file
View File

@ -0,0 +1,51 @@
{
"Messages": {
"Dispensers": "Resource Dispensers",
"Excavators": "Excavators",
"HelpText": "/gather - Shows you detailed gather information.",
"HelpTextAdmin": "To change the resources gained by gathering use the command:\r\ngather.rate <type:dispenser|pickup|quarry|survey> <resource> <multiplier>\r\nTo change the amount of resources in a dispenser type use the command:\r\ndispenser.scale <dispenser:tree|ore|corpse> <multiplier>\r\nTo change the time between Mining Quarry gathers:\r\nquarry.tickrate <seconds>",
"HelpTextMiningQuarrySpeed": "Time between Mining Quarry gathers: {0} second(s).",
"HelpTextPlayer": "Resources gained from gathering have been scaled to the following:",
"HelpTextPlayerDefault": "Default values.",
"HelpTextPlayerGains": "Resources gained from {0}:",
"InvalidArgumentsDispenserType": "Invalid arguments supplied! Use dispenser.scale <dispenser:tree|ore|corpse> <multiplier>",
"InvalidArgumentsGather": "Invalid arguments supplied! Use gather.rate <type:dispenser|pickup|quarry|survey> <resource> <multiplier>",
"InvalidArgumentsMiningQuarrySpeed": "Invalid arguments supplied! Use quarry.rate <time between gathers in seconds>",
"InvalidDispenser": "{0} is not a valid dispenser. Check gather.dispensers for a list of available options.",
"InvalidMiningQuarrySpeed": "You can't set the speed lower than 1 second!",
"InvalidModifier": "Invalid modifier supplied! The new modifier always needs to be bigger than 0!",
"InvalidResource": "{0} is not a valid resource. Check gather.resources for a list of available options.",
"MiningQuarries": "Mining Quarries",
"ModifyDispenser": "You have set the resource amount for {0} dispensers to x{1}",
"ModifyMiningQuarrySpeed": "The Mining Quarry will now provide resources every {0} seconds.",
"ModifyResource": "You have set the gather rate for {0} to x{1} from {2}.",
"ModifyResourceRemove": "You have reset the gather rate for {0} from {1}.",
"NotAllowed": "You don't have permission to use this command.",
"Pickups": "pickups",
"SurveyCharges": "Survey Charges"
},
"Options": {
"ExcavatorBeltSpeedMax": 0.1,
"ExcavatorResourceModifiers": {},
"ExcavatorResourceTickRate": 3.0,
"ExcavatorTimeForFullResources": 120.0,
"GatherDispenserModifiers": {},
"GatherResourceModifiers": {
"*": 2.0
},
"MiningQuarryResourceTickRate": 5.0,
"PickupResourceModifiers": {
"*": 2.0
},
"QuarryResourceModifiers": {
"*": 2.0
},
"SurveyResourceModifiers": {
"*": 2.0
}
},
"Settings": {
"ChatPrefix": "Gather Manager",
"ChatPrefixColor": "#008000ff"
}
}

44
config/Kits.json Normal file
View File

@ -0,0 +1,44 @@
{
"NPC - GUI Kits": {
"0": {
"description": "Welcome on this server! Here is a list of free kits that you can get.<color=green>Enjoy your stay</color>",
"kits": [
"kit1",
"kit2"
]
},
"1235439": {
"description": "Welcome on this server! Here is a list of free kits that you can get.<color=green>Enjoy your stay</color>",
"kits": [
"kit1",
"kit2"
]
},
"8753201223": {
"description": "<color=red>VIPs Kits</color>",
"kits": [
"kit1",
"kit3"
]
}
},
"CopyPaste - Parameters": [
"deployables",
"true",
"inventories",
"true"
],
"Custom AutoKits": {
"0": "KitName",
"1": "KitName",
"2": "KitName"
},
"Kit - Logging": false,
"Show All Kits": false,
"Background - URL": "",
"Wipe kit data on map wipe": false,
"Kit Names & Cooldowns - Cooldowns (minutes)": {
"kitName1": 20.0,
"kitName2": 30.0
}
}

View File

@ -0,0 +1,11 @@
{
"Chat - Message colour": "<color=white>",
"Chat - Title colour": "<color=orange>",
"GUI - All = per page": false,
"GUI - Inherited colour": "0.9 0.6 0.17 1",
"GUI - Label colour": "0.7 0.32 0.17 1",
"GUI - Off colour": "0.2 0.2 0.2 1",
"GUI - On colour": "0.7 0.32 0.17 1",
"Options - GUI Transparency 0-1": 0.9,
"Options - Plugin BlockList": ""
}

44
config/QuickSmelt.json Normal file
View File

@ -0,0 +1,44 @@
{
"Use Permission": true,
"Speed Multipliers": {
"global": 1.0,
"furnace.shortname": 1.0
},
"Fuel Usage Speed Multipliers": {
"global": 1.0,
"furnace.shortname": 1.0
},
"Fuel Usage Multipliers": {
"global": 1,
"furnace.shortname": 1
},
"Output Multipliers": {
"global": {
"global": 1.0
},
"furnace.shortname": {
"item.shortname": 1.0
}
},
"Whitelist": {
"global": [
"item.shortname"
],
"furnace.shortname": [
"item.shortname"
]
},
"Blacklist": {
"global": [
"item.shortname"
],
"furnace.shortname": [
"item.shortname"
]
},
"Smelting Frequencies (Smelt items every N smelting ticks)": {
"global": 1,
"furnace.shortname": 1
},
"Debug": false
}

22
config/TimeOfDay.json Normal file
View File

@ -0,0 +1,22 @@
{
"DatePreset": {
"presetDay": 1,
"presetMonth": 1,
"presetYear": 2020,
"setPresetDate": false
},
"Settings": {
"authLevelCmds": 1,
"authLevelFreeze": 2,
"autoSkipDay": false,
"autoSkipNight": false,
"dayLength": 30,
"freezeDate": false,
"logAutoSkipConsole": true,
"nightLength": 30
},
"TimeFreeze": {
"freezeTimeOnload": false,
"timeToFreeze": 12.0
}
}

7
config/WipeKits.json Normal file
View File

@ -0,0 +1,7 @@
{
"Kit Names & Cooldowns - Cooldowns (minutes)": {
"kitname1": 5.0,
"kitname2": 5.0
},
"Use GUI Kits (true/false)": false
}

View File

@ -0,0 +1,5 @@
{
"ItemList": [
"flare"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,685 @@
{
"version": 2279,
"AllItemsAvailable": {
"hat.wolf": "Wolf Headdress",
"fogmachine": "Fogger-3000",
"strobelight": "Strobe Light",
"kayak": "Kayak",
"minihelicopter.repair": "MC repair",
"scraptransportheli.repair": "ScrapTransportHeliRepair",
"ammo.grenadelauncher.buckshot": "40mm Shotgun Round",
"ammo.grenadelauncher.he": "40mm HE Grenade",
"ammo.grenadelauncher.smoke": "40mm Smoke Grenade",
"arrow.hv": "High Velocity Arrow",
"arrow.wooden": "Wooden Arrow",
"arrow.bone": "Bone Arrow",
"arrow.fire": "Fire Arrow",
"ammo.handmade.shell": "Handmade Shell",
"ammo.nailgun.nails": "Nailgun Nails",
"ammo.pistol": "Pistol Bullet",
"ammo.pistol.fire": "Incendiary Pistol Bullet",
"ammo.pistol.hv": "HV Pistol Ammo",
"ammo.rifle": "5.56 Rifle Ammo",
"ammo.rifle.explosive": "Explosive 5.56 Rifle Ammo",
"ammo.rifle.incendiary": "Incendiary 5.56 Rifle Ammo",
"ammo.rifle.hv": "HV 5.56 Rifle Ammo",
"ammo.rocket.basic": "Rocket",
"ammo.rocket.fire": "Incendiary Rocket",
"ammo.rocket.hv": "High Velocity Rocket",
"ammo.rocket.smoke": "Smoke Rocket WIP!!!!",
"ammo.shotgun": "12 Gauge Buckshot",
"ammo.shotgun.fire": "12 Gauge Incendiary Shell",
"ammo.shotgun.slug": "12 Gauge Slug",
"door.double.hinged.metal": "Sheet Metal Double Door",
"door.double.hinged.toptier": "Armored Double Door",
"door.double.hinged.wood": "Wood Double Door",
"door.hinged.metal": "Sheet Metal Door",
"door.hinged.toptier": "Armored Door",
"door.hinged.wood": "Wooden Door",
"floor.grill": "Floor grill",
"floor.ladder.hatch": "Ladder Hatch",
"floor.triangle.grill": "Floor triangle grill",
"floor.triangle.ladder.hatch": "Triangle Ladder Hatch",
"gates.external.high.stone": "High External Stone Gate",
"gates.external.high.wood": "High External Wooden Gate",
"ladder.wooden.wall": "Wooden Ladder",
"wall.external.high.stone": "High External Stone Wall",
"wall.external.high": "High External Wooden Wall",
"wall.frame.cell.gate": "Prison Cell Gate",
"wall.frame.cell": "Prison Cell Wall",
"wall.frame.fence.gate": "Chainlink Fence Gate",
"wall.frame.fence": "Chainlink Fence",
"wall.frame.garagedoor": "Garage Door",
"wall.frame.netting": "Netting",
"wall.frame.shopfront": "Shop Front",
"wall.frame.shopfront.metal": "Metal Shop Front",
"wall.window.bars.metal": "Metal Window Bars",
"wall.window.bars.toptier": "Reinforced Glass Window",
"wall.window.bars.wood": "Wooden Window Bars",
"shutter.metal.embrasure.a": "Metal horizontal embrasure",
"shutter.metal.embrasure.b": "Metal Vertical embrasure",
"wall.window.glass.reinforced": "Strengthened Glass Window",
"shutter.wood.a": "Wood Shutters",
"watchtower.wood": "Watch Tower",
"diving.fins": "Diving Fins",
"diving.mask": "Diving Mask",
"diving.tank": "Diving Tank",
"diving.wetsuit": "Wetsuit",
"boots.frog": "Frog Boots",
"barrelcostume": "A Barrel Costume",
"cratecostume": "Crate Costume",
"burlap.gloves.new": "Burlap Gloves",
"burlap.gloves": "Leather Gloves",
"roadsign.gloves": "Roadsign Gloves",
"tactical.gloves": "Tactical Gloves",
"ghostsheet": "Ghost Costume",
"halloween.mummysuit": "Mummy Suit",
"scarecrow.suit": "Scarecrow Suit",
"scarecrowhead": "Scarecrow Wrap",
"attire.hide.helterneck": "Hide Halterneck",
"hat.beenie": "Beenie Hat",
"hat.boonie": "Boonie Hat",
"bucket.helmet": "Bucket Helmet",
"burlap.headwrap": "Burlap Headwrap",
"hat.candle": "Candle Hat",
"hat.cap": "Baseball Cap",
"clatter.helmet": "Clatter Helmet",
"coffeecan.helmet": "Coffee Can Helmet",
"deer.skull.mask": "Bone Helmet",
"heavy.plate.helmet": "Heavy Plate Helmet",
"hat.miner": "Miners Hat",
"partyhat": "Party Hat",
"riot.helmet": "Riot Helmet",
"wood.armor.helmet": "Wood Armor Helmet",
"hoodie": "Hoodie",
"bone.armor.suit": "Bone Armor",
"heavy.plate.jacket": "Heavy Plate Jacket",
"jacket.snow": "Snow Jacket",
"jacket": "Jacket",
"wood.armor.jacket": "Wood Chestplate",
"mask.balaclava": "Improvised Balaclava",
"mask.bandana": "Bandana Mask",
"metal.facemask": "Metal Facemask",
"nightvisiongoggles": "Night Vision Goggles",
"burlap.trousers": "Burlap Trousers",
"heavy.plate.pants": "Heavy Plate Pants",
"attire.hide.pants": "Hide Pants",
"roadsign.kilt": "Road Sign Kilt",
"pants.shorts": "Shorts",
"wood.armor.pants": "Wood Armor Pants",
"pants": "Pants",
"attire.hide.poncho": "Hide Poncho",
"burlap.shirt": "Burlap Shirt",
"shirt.collared": "Shirt",
"attire.hide.vest": "Hide Vest",
"shirt.tanktop": "Tank Top",
"shoes.boots": "Boots",
"burlap.shoes": "Burlap Shoes",
"attire.hide.boots": "Hide Boots",
"attire.hide.skirt": "Hide Skirt",
"attire.banditguard": "Bandit Guard Gear",
"hazmatsuit": "Hazmat Suit",
"hazmatsuit_scientist": "Scientist Suit",
"hazmatsuit_scientist_peacekeeper": "Scientist Suit",
"hazmatsuit.spacesuit": "Space Suit",
"scientistsuit_heavy": "Heavy Scientist Suit",
"tshirt.long": "Longsleeve T-Shirt",
"tshirt": "T-Shirt",
"metal.plate.torso": "Metal Chest Plate",
"roadsign.jacket": "Road Sign Jacket",
"bleach": "Bleach",
"ducttape": "Duct Tape",
"carburetor1": "Low Quality Carburetor",
"carburetor2": "Medium Quality Carburetor",
"carburetor3": "High Quality Carburetor",
"crankshaft1": "Low Quality Crankshaft",
"crankshaft2": "Medium Quality Crankshaft",
"crankshaft3": "High Quality Crankshaft",
"piston1": "Low Quality Pistons",
"piston2": "Medium Quality Pistons",
"piston3": "High Quality Pistons",
"sparkplug1": "Low Quality Spark Plugs",
"sparkplug2": "Medium Quality Spark Plugs",
"sparkplug3": "High Quality Spark Plugs",
"valve1": "Low Quality Valves",
"valve2": "Medium Quality Valves",
"valve3": "High Quality Valves",
"fuse": "Electric Fuse",
"gears": "Gears",
"glue": "Glue",
"metalblade": "Metal Blade",
"metalpipe": "Metal Pipe",
"propanetank": "Empty Propane Tank",
"roadsigns": "Road Signs",
"rope": "Rope",
"sewingkit": "Sewing Kit",
"sheetmetal": "Sheet Metal",
"metalspring": "Metal Spring",
"sticks": "Sticks",
"tarp": "Tarp",
"techparts": "Tech Trash",
"riflebody": "Rifle Body",
"semibody": "Semi Automatic Body",
"smgbody": "SMG Body",
"barricade.concrete": "Concrete Barricade",
"barricade.wood.cover": "Wooden Barricade Cover",
"barricade.metal": "Metal Barricade",
"barricade.sandbags": "Sandbag Barricade",
"barricade.stone": "Stone Barricade",
"barricade.wood": "Wooden Barricade",
"barricade.woodwire": "Barbed Wooden Barricade",
"bbq": "Barbeque",
"trap.bear": "Snap Trap",
"bed": "Bed",
"campfire": "Camp Fire",
"ceilinglight": "Ceiling Light",
"chair": "Chair",
"composter": "Composter",
"computerstation": "Computer Station",
"drone": "Drone",
"dropbox": "Drop Box",
"elevator": "Elevator",
"fireplace.stone": "Stone Fireplace",
"firework.boomer.blue": "Blue Boomer",
"firework.boomer.champagne": "Champagne Boomer",
"firework.boomer.green": "Green Boomer",
"firework.boomer.orange": "Orange Boomer",
"firework.boomer.red": "Red Boomer",
"firework.boomer.violet": "Violet Boomer",
"firework.romancandle.blue": "Blue Roman Candle",
"firework.romancandle.green": "Green Roman Candle",
"firework.romancandle.red": "Red Roman Candle",
"firework.romancandle.violet": "Violet Roman Candle",
"firework.volcano": "White Volcano Firework",
"firework.volcano.red": "Red Volcano Firework",
"firework.volcano.violet": "Violet Volcano Firework",
"spikes.floor": "Wooden Floor Spikes",
"fridge": "Fridge",
"furnace.large": "Large Furnace",
"furnace": "Furnace",
"hitchtroughcombo": "Hitch & Trough",
"habrepair": "Hab Repair",
"jackolantern.angry": "Jack O Lantern Angry",
"jackolantern.happy": "Jack O Lantern Happy",
"trap.landmine": "Land Mine",
"lantern": "Lantern",
"box.wooden.large": "Large Wood Box",
"water.barrel": "Water Barrel",
"locker": "Locker",
"mailbox": "Mail Box",
"mixingtable": "Mixing Table",
"modularcarlift": "Modular Car Lift",
"mining.pumpjack": "Pump Jack",
"small.oil.refinery": "Small Oil Refinery",
"planter.large": "Large Planter Box",
"planter.small": "Small Planter Box",
"electric.audioalarm": "Audio Alarm",
"smart.alarm": "Smart Alarm",
"smart.switch": "Smart Switch",
"storage.monitor": "Storage Monitor",
"electric.battery.rechargable.large": "Large Rechargable Battery",
"electric.battery.rechargable.medium": "Medium Rechargable Battery",
"electric.battery.rechargable.small": "Small Rechargable Battery",
"electric.button": "Button",
"electric.counter": "Counter",
"electric.hbhfsensor": "HBHF Sensor",
"electric.laserdetector": "Laser Detector",
"electric.pressurepad": "Pressure Pad",
"electric.doorcontroller": "Door Controller",
"electric.heater": "Electric Heater",
"fluid.combiner": "Fluid Combiner",
"fluid.splitter": "Fluid Splitter",
"fluid.switch": "Fluid Switch & Pump",
"electric.andswitch": "AND Switch",
"electric.blocker": "Blocker",
"electrical.branch": "Electrical Branch",
"electrical.combiner": "Root Combiner",
"electrical.memorycell": "Memory Cell",
"electric.orswitch": "OR Switch",
"electric.random.switch": "RAND Switch",
"electric.rf.broadcaster": "RF Broadcaster",
"electric.rf.receiver": "RF Receiver",
"electric.xorswitch": "XOR Switch",
"electric.fuelgenerator.small": "Small Generator",
"electric.generator.small": "Test Generator",
"electric.solarpanel.large": "Large Solar Panel",
"electric.igniter": "Igniter",
"electric.flasherlight": "Flasher Light",
"electric.simplelight": "Simple Light",
"electric.sirenlight": "Siren Light",
"powered.water.purifier": "Powered Water Purifier",
"electric.switch": "Switch",
"electric.splitter": "Splitter",
"electric.sprinkler": "Sprinkler",
"electric.teslacoil": "Tesla Coil",
"electric.timer": "Timer",
"electric.cabletunnel": "Cable Tunnel",
"waterpump": "Water Pump",
"mining.quarry": "Mining Quarry",
"target.reactive": "Reactive Target",
"box.repair.bench": "Repair Bench",
"research.table": "Research Table",
"rug.bear": "Rug Bear Skin",
"rug": "Rug",
"searchlight": "Search Light",
"secretlabchair": "Secret Lab Chair",
"shelves": "Salvaged Shelves",
"sign.hanging.banner.large": "Large Banner Hanging",
"sign.hanging": "Two Sided Hanging Sign",
"sign.hanging.ornate": "Two Sided Ornate Hanging Sign",
"sign.pictureframe.landscape": "Landscape Picture Frame",
"sign.pictureframe.portrait": "Portrait Picture Frame",
"sign.pictureframe.tall": "Tall Picture Frame",
"sign.pictureframe.xl": "XL Picture Frame",
"sign.pictureframe.xxl": "XXL Picture Frame",
"sign.pole.banner.large": "Large Banner on pole",
"sign.post.double": "Double Sign Post",
"sign.post.single": "Single Sign Post",
"sign.post.town": "One Sided Town Sign Post",
"sign.post.town.roof": "Two Sided Town Sign Post",
"sign.wooden.huge": "Huge Wooden Sign",
"sign.wooden.large": "Large Wooden Sign",
"sign.wooden.medium": "Medium Wooden Sign",
"sign.wooden.small": "Small Wooden Sign",
"guntrap": "Shotgun Trap",
"sleepingbag": "Sleeping Bag",
"stash.small": "Small Stash",
"sofa": "Sofa",
"spinner.wheel": "Spinning wheel",
"fishtrap.small": "Survival Fish Trap",
"table": "Table",
"workbench1": "Work Bench Level 1",
"workbench2": "Work Bench Level 2",
"workbench3": "Work Bench Level 3",
"cupboard.tool": "Tool Cupboard",
"tunalight": "Tuna Can Lamp",
"vending.machine": "Vending Machine",
"water.catcher.large": "Large Water Catcher",
"water.catcher.small": "Small Water Catcher",
"water.purifier": "Water Purifier",
"generator.wind.scrap": "Wind Turbine",
"box.wooden": "Wood Storage Box",
"apple": "Apple",
"apple.spoiled": "Rotten Apple",
"black.raspberries": "Black Raspberries",
"blueberries": "Blueberries",
"botabag": "Bota Bag",
"cactusflesh": "Cactus Flesh",
"can.beans": "Can of Beans",
"can.tuna": "Can of Tuna",
"chocholate": "Chocolate Bar",
"fish.cooked": "Cooked Fish",
"fish.raw": "Raw Fish",
"fish.minnows": "Minnows",
"fish.troutsmall": "Small Trout",
"granolabar": "Granola Bar",
"chicken.burned": "Burnt Chicken",
"chicken.cooked": "Cooked Chicken",
"chicken.raw": "Raw Chicken Breast",
"chicken.spoiled": "Spoiled Chicken",
"deermeat.burned": "Burnt Deer Meat",
"deermeat.cooked": "Cooked Deer Meat",
"deermeat.raw": "Raw Deer Meat",
"horsemeat.burned": "Burnt Horse Meat",
"horsemeat.cooked": "Cooked Horse Meat",
"horsemeat.raw": "Raw Horse Meat",
"humanmeat.burned": "Burnt Human Meat",
"humanmeat.cooked": "Cooked Human Meat",
"humanmeat.raw": "Raw Human Meat",
"humanmeat.spoiled": "Spoiled Human Meat",
"bearmeat.burned": "Burnt Bear Meat",
"bearmeat.cooked": "Cooked Bear Meat",
"bearmeat": "Raw Bear Meat",
"wolfmeat.burned": "Burnt Wolf Meat",
"wolfmeat.cooked": "Cooked Wolf Meat",
"wolfmeat.raw": "Raw Wolf Meat",
"wolfmeat.spoiled": "Spoiled Wolf Meat",
"meat.pork.burned": "Burnt Pork",
"meat.pork.cooked": "Cooked Pork",
"meat.boar": "Raw Pork",
"mushroom": "Mushroom",
"jar.pickle": "Pickles",
"smallwaterbottle": "Small Water Bottle",
"waterjug": "Water Jug",
"fun.bass": "Shovel Bass",
"fun.cowbell": "Cowbell",
"drumkit": "Junkyard Drum Kit",
"fun.flute": "Pan Flute",
"fun.guitar": "Acoustic Guitar",
"fun.jerrycanguitar": "Jerry Can Guitar",
"piano": "Wheelbarrow Piano",
"fun.tambourine": "Canbourine",
"fun.trumpet": "Plumber's Trumpet",
"fun.tuba": "Sousaphone",
"xylophone": "Xylobone",
"car.key": "Car Key",
"door.key": "Door Key",
"lock.key": "Key Lock",
"lock.code": "Code Lock",
"blueprintbase": "Blueprint",
"chineselantern": "Chinese Lantern",
"dragondoorknocker": "Dragon Door Knocker",
"hat.dragonmask": "Dragon Mask",
"newyeargong": "New Year Gong",
"hat.oxmask": "Ox Mask",
"hat.ratmask": "Rat Mask",
"lunar.firecrackers": "Firecracker String",
"arcade.machine.chippy": "Chippy Arcade Game",
"door.closer": "Door Closer",
"attire.bunnyears": "Bunny Ears",
"attire.bunny.onesie": "Bunny Onesie",
"easterdoorwreath": "Easter Door Wreath",
"easterbasket": "Egg Basket",
"rustige_egg_a": "Rustigé Egg - Red",
"rustige_egg_b": "Rustigé Egg - Blue",
"rustige_egg_c": "Rustigé Egg - Purple",
"rustige_egg_d": "Rustigé Egg - Ivory",
"attire.nesthat": "Nest Hat",
"easter.bronzeegg": "Bronze Egg",
"easter.goldegg": "Gold Egg",
"easter.paintedeggs": "Painted Egg",
"easter.silveregg": "Silver Egg",
"halloween.candy": "Halloween Candy",
"largecandles": "Large Candle Set",
"smallcandles": "Small Candle Set",
"coffin.storage": "Coffin",
"cursedcauldron": "Cursed Cauldron",
"gravestone": "Gravestone",
"woodcross": "Wooden Cross",
"wall.graveyard.fence": "Graveyard Fence",
"halloween.lootbag.large": "Large Loot Bag",
"halloween.lootbag.medium": "Medium Loot Bag",
"halloween.lootbag.small": "Small Loot Bag",
"pumpkinbasket": "Pumpkin Bucket",
"scarecrow": "Scarecrow",
"skullspikes.candles": "Skull Spikes",
"skullspikes.pumpkin": "Skull Spikes",
"skullspikes": "Skull Spikes",
"skulldoorknocker": "Skull Door Knocker",
"skull_fire_pit": "Skull Fire Pit",
"spiderweb": "Spider Webs",
"spookyspeaker": "Spooky Speaker",
"halloween.surgeonsuit": "Surgeon Scrubs",
"skull.trophy.jar": "Skull Trophy",
"skull.trophy.jar2": "Skull Trophy",
"skull.trophy.table": "Skull Trophy",
"skull.trophy": "Skull Trophy",
"movembermoustachecard": "Card Movember Moustache",
"movembermoustache": "Movember Moustache",
"note": "Note",
"skull.human": "Human Skull",
"abovegroundpool": "Above Ground Pool",
"beachchair": "Beach Chair",
"beachparasol": "Beach Parasol",
"beachtable": "Beach Table",
"beachtowel": "Beach Towel",
"boogieboard": "Boogie Board",
"innertube": "Inner Tube",
"innertube.horse": "Inner Tube",
"innertube.unicorn": "Inner Tube",
"tool.instant_camera": "Instant Camera",
"paddlingpool": "Paddling Pool",
"photo": "Photograph",
"photoframe.landscape": "Landscape Photo Frame",
"photoframe.large": "Large Photo Frame",
"photoframe.portrait": "Portrait Photo Frame",
"sunglasses02black": "Sunglasses",
"sunglasses02camo": "Sunglasses",
"sunglasses02red": "Sunglasses",
"sunglasses03black": "Sunglasses",
"sunglasses03chrome": "Sunglasses",
"sunglasses03gold": "Sunglasses",
"sunglasses": "Sunglasses",
"gun.water": "Water Gun",
"pistol.water": "Water Pistol",
"twitchsunglasses": "Purple Sunglasses",
"twitch.headset": "Headset",
"hobobarrel": "Hobo Barrel",
"door.hinged.industrial.a": "Industrial Door",
"candycaneclub": "Candy Cane Club",
"xmas.lightstring": "Christmas Lights",
"xmas.door.garland": "Festive Doorway Garland",
"candycane": "Candy Cane",
"giantcandycanedecor": "Giant Candy Decor",
"wall.ice.wall": "Short Ice Wall",
"wall.external.high.ice": "High Ice Wall",
"giantlollipops": "Giant Lollipop Decor",
"sign.neon.125x125": "Small Neon Sign",
"sign.neon.125x215.animated": "Medium Animated Neon Sign",
"sign.neon.125x215": "Medium Neon Sign",
"sign.neon.xl.animated": "Large Animated Neon Sign",
"sign.neon.xl": "Large Neon Sign",
"pookie.bear": "Pookie Bear",
"xmas.lightstring.advanced": "Deluxe Christmas Lights",
"coal": "Coal :(",
"xmas.present.large": "Large Present",
"xmas.present.medium": "Medium Present",
"xmas.present.small": "Small Present",
"sled.xmas": "Sled",
"sled": "Sled",
"snowmachine": "Snow Machine",
"snowball": "Snowball",
"ammo.snowballgun": "",
"snowballgun": "Snowball Gun",
"snowman": "Snowman",
"stocking.large": "SUPER Stocking",
"stocking.small": "Small Stocking",
"attire.reindeer.headband": "Reindeer Antlers",
"santabeard": "Santa Beard",
"santahat": "Santa Hat",
"xmas.window.garland": "Festive Window Garland",
"wrappedgift": "Wrapped Gift",
"wrappingpaper": "Wrapping Paper",
"xmasdoorwreath": "Christmas Door Wreath",
"xmas.decoration.baubels": "Decorative Baubels",
"xmas.decoration.candycanes": "Decorative Plastic Candy Canes",
"xmas.decoration.gingerbreadmen": "Decorative Gingerbread Men",
"xmas.decoration.lights": "Tree Lights",
"xmas.decoration.pinecone": "Decorative Pinecones",
"xmas.decoration.star": "Star Tree Topper",
"xmas.decoration.tinsel": "Decorative Tinsel",
"xmas.tree": "Christmas Tree",
"autoturret": "Auto Turret",
"flameturret": "Flame Turret",
"gloweyes": "Glowing Eyes",
"ammo.rocket.sam": "SAM Ammo",
"samsite": "SAM Site",
"black.berry": "Black Berry",
"clone.black.berry": "Black Berry Clone",
"seed.black.berry": "Black Berry Seed",
"blue.berry": "Blue Berry",
"clone.blue.berry": "Blue Berry Clone",
"seed.blue.berry": "Blue Berry Seed",
"green.berry": "Green Berry",
"clone.green.berry": "Green Berry Clone",
"seed.green.berry": "Green Berry Seed",
"red.berry": "Red Berry",
"clone.red.berry": "Red Berry Clone",
"seed.red.berry": "Red Berry Seed",
"white.berry": "White Berry",
"clone.white.berry": "White Berry Clone",
"seed.white.berry": "White Berry Seed",
"yellow.berry": "Yellow Berry",
"clone.yellow.berry": "Yellow Berry Clone",
"seed.yellow.berry": "Yellow Berry Seed",
"corn": "Corn",
"clone.corn": "Corn Clone",
"seed.corn": "Corn Seed",
"clone.hemp": "Hemp Clone",
"seed.hemp": "Hemp Seed",
"potato": "Potato",
"clone.potato": "Potato Clone",
"seed.potato": "Potato Seed",
"pumpkin": "Pumpkin",
"clone.pumpkin": "Pumpkin Plant Clone",
"seed.pumpkin": "Pumpkin Seed",
"fat.animal": "Animal Fat",
"battery.small": "Battery - Small",
"blood": "Blood",
"bone.fragments": "Bone Fragments",
"cctv.camera": "CCTV Camera",
"charcoal": "Charcoal",
"cloth": "Cloth",
"crude.oil": "Crude Oil",
"diesel_barrel": "Diesel Fuel",
"can.beans.empty": "Empty Can Of Beans",
"can.tuna.empty": "Empty Tuna Can",
"explosives": "Explosives",
"fertilizer": "Fertilizer",
"gunpowder": "Gun Powder",
"horsedung": "Horse Dung",
"hq.metal.ore": "High Quality Metal Ore",
"metal.refined": "High Quality Metal",
"leather": "Leather",
"lowgradefuel": "Low Grade Fuel",
"metal.fragments": "Metal Fragments",
"metal.ore": "Metal Ore",
"paper": "Paper",
"plantfiber": "Plant Fiber",
"researchpaper": "Research Paper",
"water.salt": "Salt Water",
"scrap": "Scrap",
"stones": "Stones",
"sulfur.ore": "Sulfur Ore",
"sulfur": "Sulfur",
"targeting.computer": "Targeting Computer",
"water": "Water",
"skull.wolf": "Wolf Skull",
"wood": "Wood",
"healingtea.advanced": "Advanced Healing Tea",
"healingtea": "Basic Healing Tea",
"healingtea.pure": "Pure Healing Tea",
"maxhealthtea.advanced": "Advanced Max Health Tea",
"maxhealthtea": "Basic Max Health Tea",
"maxhealthtea.pure": "Pure Max Health Tea",
"oretea.advanced": "Advanced Ore Tea",
"oretea": "Basic Ore Tea",
"oretea.pure": "Pure Ore Tea",
"radiationremovetea.advanced": "Advanced Rad. Removal Tea",
"radiationremovetea": "Rad. Removal Tea",
"radiationremovetea.pure": "Pure Rad. Removal Tea",
"radiationresisttea.advanced": "Adv. Anti-Rad Tea",
"radiationresisttea": "Anti-Rad Tea",
"radiationresisttea.pure": "Pure Anti-Rad Tea",
"scraptea.advanced": "Advanced Scrap Tea",
"scraptea": "Basic Scrap Tea",
"scraptea.pure": "Pure Scrap Tea",
"woodtea.advanced": "Advanced Wood Tea",
"woodtea": "Basic Wood Tea",
"woodtea.pure": "Pure Wood Tea",
"antiradpills": "Anti-Radiation Pills",
"tool.binoculars": "Binoculars",
"explosive.timed": "Timed Explosive Charge",
"tool.camera": "Camera",
"rf.detonator": "RF Transmitter",
"fishingrod.handmade": "Handmade Fishing Rod",
"flare": "Flare",
"flashlight.held": "Flashlight",
"geiger.counter": "Geiger Counter",
"hosetool": "Hose Tool",
"jackhammer": "Jackhammer",
"keycard_blue": "Blue Keycard",
"keycard_green": "Green Keycard",
"keycard_red": "Red Keycard",
"largemedkit": "Large Medkit",
"map": "Paper Map",
"syringe.medical": "Medical Syringe",
"rf_pager": "RF Pager",
"building.planner": "Building Plan",
"grenade.smoke": "Smoke Grenade",
"supply.signal": "Supply Signal",
"surveycharge": "Survey Charge",
"wiretool": "Wire Tool",
"vehicle.chassis.2mod": "Small Chassis",
"vehicle.chassis.3mod": "Medium Chassis",
"vehicle.chassis.4mod": "Large Chassis",
"vehicle.chassis": "Generic vehicle chassis",
"vehicle.1mod.cockpit": "Cockpit Vehicle Module",
"vehicle.1mod.cockpit.armored": "Armored Cockpit Vehicle Module",
"vehicle.1mod.cockpit.with.engine": "Cockpit With Engine Vehicle Module",
"vehicle.1mod.engine": "Engine Vehicle Module",
"vehicle.1mod.flatbed": "Flatbed Vehicle Module",
"vehicle.1mod.passengers.armored": "Armored Passenger Vehicle Module",
"vehicle.1mod.rear.seats": "Rear Seats Vehicle Module",
"vehicle.1mod.storage": "Storage Vehicle Module",
"vehicle.1mod.taxi": "Taxi Vehicle Module",
"vehicle.2mod.flatbed": "Large Flatbed Vehicle Module",
"vehicle.2mod.fuel.tank": "Fuel Tank Vehicle Module",
"vehicle.2mod.passengers": "Passenger Vehicle Module",
"vehicle.module": "Generic vehicle module",
"telephone": "Telephone",
"weapon.mod.8x.scope": "16x Zoom Scope",
"weapon.mod.flashlight": "Weapon flashlight",
"weapon.mod.holosight": "Holosight",
"weapon.mod.lasersight": "Weapon Lasersight",
"weapon.mod.muzzleboost": "Muzzle Boost",
"weapon.mod.muzzlebrake": "Muzzle Brake",
"weapon.mod.simplesight": "Simple Handmade Sight",
"weapon.mod.silencer": "Silencer",
"weapon.mod.small.scope": "8x Zoom Scope",
"rifle.ak": "Assault Rifle",
"bandage": "Bandage",
"grenade.beancan": "Beancan Grenade",
"rifle.bolt": "Bolt Action Rifle",
"bone.club": "Bone Club",
"knife.bone": "Bone Knife",
"bow.hunting": "Hunting Bow",
"cakefiveyear": "Birthday Cake",
"chainsaw": "Chainsaw",
"salvaged.cleaver": "Salvaged Cleaver",
"bow.compound": "Compound Bow",
"crossbow": "Crossbow",
"shotgun.double": "Double Barrel Shotgun",
"pistol.eoka": "Eoka Pistol",
"grenade.f1": "F1 Grenade",
"flamethrower": "Flame Thrower",
"multiplegrenadelauncher": "Multiple Grenade Launcher",
"knife.butcher": "Butcher Knife",
"pitchfork": "Pitchfork",
"sickle": "Sickle",
"hammer": "Hammer",
"hatchet": "Hatchet",
"knife.combat": "Combat Knife",
"rifle.l96": "L96 Rifle",
"rifle.lr300": "LR-300 Assault Rifle",
"lmg.m249": "M249",
"rifle.m39": "M39 Rifle",
"pistol.m92": "M92 Pistol",
"mace": "Mace",
"machete": "Machete",
"smg.mp5": "MP5A4",
"pistol.nailgun": "Nailgun",
"paddle": "Paddle",
"pickaxe": "Pickaxe",
"shotgun.waterpipe": "Waterpipe Shotgun",
"pistol.python": "Python Revolver",
"pistol.revolver": "Revolver",
"rock": "Rock",
"rocket.launcher": "Rocket Launcher",
"axe.salvaged": "Salvaged Axe",
"hammer.salvaged": "Salvaged Hammer",
"icepick.salvaged": "Salvaged Icepick",
"explosive.satchel": "Satchel Charge",
"shotgun.pump": "Pump Shotgun",
"pistol.semiauto": "Semi-Automatic Pistol",
"rifle.semiauto": "Semi-Automatic Rifle",
"smg.2": "Custom SMG",
"shotgun.spas12": "Spas-12 Shotgun",
"stonehatchet": "Stone Hatchet",
"stone.pickaxe": "Stone Pickaxe",
"spear.stone": "Stone Spear",
"longsword": "Longsword",
"salvaged.sword": "Salvaged Sword",
"smg.thompson": "Thompson",
"toolgun": "Garry's Mod Tool Gun",
"torch": "Torch",
"bucket.water": "Water Bucket",
"spear.wooden": "Wooden Spear",
"horse.armor.roadsign": "Roadsign Horse Armor",
"horse.armor.wood": "Wooden Horse Armor",
"horse.saddle": "Horse Saddle",
"horse.saddlebag": "Saddle bag",
"horse.shoes.advanced": "High Quality Horse Shoes",
"horse.shoes.basic": "Basic Horse Shoes"
}
}

3
data/Kits.json Normal file
View File

@ -0,0 +1,3 @@
{
"Kits": {}
}

1
data/Kits_Data.json Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,6 @@
-
76561198106966240ŕńůĹ<C5AF>€€<E282AC> Sick Prodigy
+
76561198017312452Äí™<E284A2>€€<E282AC>
Dunkeykong

BIN
data/oxide.groups.data Normal file

Binary file not shown.

4
data/oxide.lang.data Normal file
View File

@ -0,0 +1,4 @@
en
76561198106966240en
76561198017312452en

8
data/oxide.users.data Normal file
View File

@ -0,0 +1,8 @@
3
76561198106966240
default
admin Sick Prodigy
'
76561198017312452
defaultUnnamed

View File

@ -0,0 +1,27 @@
{
"NoInvSpace": "You don't have enough room to craft this item!",
"NoPerms": "You don't have permission to use this command.",
"CannotFindItem": "Cannot find item {0}.",
"ItemBlocked": "{0} has been blocked from crafting.",
"ItemUnblocked": "{0} has been unblocked from crafting.",
"NeedsAdvancedOptions": "You need to enable advanced crafting options in your config to use this.",
"WrongNumberInput": "Your input needs to be a number.",
"ItemCraftTimeSet": "{0} craft time set to {1} seconds",
"WorkbenchLevelSet": "{0} workbench level set to {1}",
"CurrentCraftinRate": "The current crafting rate is {0 }%",
"CraftingRateUpdated": "The crafting rate was updated to {0} %",
"CraftTime2Args": "This command needs two arguments in the format /crafttime item.shortname timetocraft",
"BlockItem1Args": "This command needs one argument in the format /blockitem item.shortname",
"UnblockItem1Args": "This command needs one argument in the format /unblockitem item.shortname",
"WorckBenchLvl2Args": "This command needs two arguments in the format /benchlvl item.shortname workbenchlvl",
"BenchLevelInput": "The work bench level must be between 0 and 3",
"SetSkin2Args": "This command needs one argument in the format /setcraftskin item.shortname skinworkshopid",
"SkinSet": "The default skin for {0} was set to {1}",
"CraftTimeCheck": "The craft time of this item is {0}",
"CommandCraftingRate": "craftrate",
"CommandCraftTime": "crafttime",
"CommandBlockItem": "blockitem",
"CommandUnblockItem": "unblockitem",
"CommandWorkbenchLVL": "benchlvl",
"CommandSetDefaultSkin": "setcraftskin"
}

33
lang/en/Kits.json Normal file
View File

@ -0,0 +1,33 @@
{
"title": "Kits: ",
"Name": "Name",
"Description": "Description",
"Redeem": "Redeem",
"AddKit": "Add Kit",
"Close": "Close",
"NoKitsFound": "All Available Kits are already in this Menu!",
"AddKitToMenu": "Select a Kit to Add to this Menu",
"KitCooldown": "Cooldown: {0}",
"Unavailable": "Unavailable",
"Last": "Last",
"Next": "Next",
"Back": "Back",
"First": "First",
"RemoveKit": "Remove Kit?",
"KitUses": "Uses: {0}",
"NoInventorySpace": "You do not have enough inventory space for this Kit!",
"Unlimited": "Unlimited",
"None": "None",
"KitRedeemed": "Kit Redeemed",
"Emptykitname": "Empty Kit Name",
"KitExistError": "This kit doesn't exist",
"CantRedeemNow": "You are not allowed to redeem a kit at the moment",
"NoAuthToRedeem": "You don't have the Auth Level to use this kit",
"NoPermKit": "You don't have the permissions to use this kit",
"NoRemainingUses": "You already redeemed all of these kits",
"CooldownMessage": "You need to wait {0} seconds to use this kit",
"WipeCooldownMessage": "You need to wait {0} seconds to use this kit since it recently wiped",
"NPCError": "You must find the NPC that gives this kit to redeem it.",
"PastingError": "Something went wrong while pasting, is CopyPaste installed?",
"NoKitFound": "This kit doesn't exist"
}

View File

@ -0,0 +1,24 @@
{
"title": "Permissions Manager: ",
"NoGroup": "Group {0} was not found.",
"NoPlayer": "Player {0} was not found.",
"GUIAll": "Grant All",
"GUINone": "Revoke All",
"GUIBack": "Back",
"GUIGroups": "Groups",
"GUIPlayers": "Players",
"GUIInherited": "Inherited",
"GUIInheritedFrom": "Inherited from",
"GUIGranted": "Granted",
"GUIRevoked": "Revoked",
"GUIName": "Permissions for {0}",
"GUIGroupsFor": "Groups for {0}",
"GUIPlayersIn": "Players in {0}",
"removePlayers": "Remove All Players",
"confirm": "Confirm",
"cancel": "Cancel",
"NotAdmin": "You need Auth Level 2, or permission, to use this command.",
"Back": "Back",
"All": "All",
"Syntax": "Use /perms, /perms player *name*, or /perms group *name*"
}

67
lang/en/RustCore.json Normal file
View File

@ -0,0 +1,67 @@
{
"CommandUsageExtLoad": "Usage: oxide.ext.load <extname>+",
"CommandUsageExtUnload": "Usage: oxide.ext.unload <extname>+",
"CommandUsageExtReload": "Usage: oxide.ext.reload <extname>+",
"CommandUsageGrant": "Usage: oxide.grant <group|user> <name|id> <permission>",
"CommandUsageGroup": "Usage: oxide.group <add|set> <name> [title] [rank]",
"CommandUsageGroupParent": "Usage: oxide.group <parent> <name> <parentName>",
"CommandUsageGroupRemove": "Usage: oxide.group <remove> <name>",
"CommandUsageLang": "Usage: oxide.lang <two-digit language code>",
"CommandUsageLoad": "Usage: oxide.load *|<pluginname>+",
"CommandUsageReload": "Usage: oxide.reload *|<pluginname>+",
"CommandUsageRevoke": "Usage: oxide.revoke <group|user> <name|id> <permission>",
"CommandUsageShow": "Usage: oxide.show <groups|perms>",
"CommandUsageShowName": "Usage: oxide.show <group|user> <name>",
"CommandUsageUnload": "Usage: oxide.unload *|<pluginname>+",
"CommandUsageUserGroup": "Usage: oxide.usergroup <add|remove> <username> <groupname>",
"ConnectionRejected": "Connection was rejected",
"DataSaved": "Saving Oxide data...",
"GroupAlreadyExists": "Group '{0}' already exists",
"GroupAlreadyHasPermission": "Group '{0}' already has permission '{1}'",
"GroupDoesNotHavePermission": "Group '{0}' does not have permission '{1}'",
"GroupChanged": "Group '{0}' changed",
"GroupCreated": "Group '{0}' created",
"GroupDeleted": "Group '{0}' deleted",
"GroupNotFound": "Group '{0}' doesn't exist",
"GroupParentChanged": "Group '{0}' parent changed to '{1}'",
"GroupParentNotChanged": "Group '{0}' parent was not changed",
"GroupParentNotFound": "Group parent '{0}' doesn't exist",
"GroupPermissionGranted": "Group '{0}' granted permission '{1}'",
"GroupPermissionRevoked": "Group '{0}' revoked permission '{1}'",
"GroupPermissions": "Group '{0}' permissions",
"GroupPlayers": "Group '{0}' players",
"Groups": "Groups",
"NoGroupPermissions": "No permissions currently granted",
"NoPermissionGroups": "No groups with this permission",
"NoPermissionPlayers": "No players with this permission",
"NoPluginsFound": "No plugins are currently available",
"NoPlayerGroups": "Player is not assigned to any groups",
"NoPlayerPermissions": "No permissions currently granted",
"NoPlayersInGroup": "No players currently in group",
"NotAllowed": "You are not allowed to use the '{0}' command",
"ParentGroupPermissions": "Parent group '{0}' permissions",
"PermissionGroups": "Permission '{0}' Groups",
"PermissionPlayers": "Permission '{0}' Players",
"PermissionNotFound": "Permission '{0}' doesn't exist",
"Permissions": "Permissions",
"PermissionsNotLoaded": "Unable to load permission files! Permissions will not work until resolved.\n => {0}",
"PlayerLanguage": "Player language set to {0}",
"PluginNotLoaded": "Plugin '{0}' not loaded.",
"PluginReloaded": "Reloaded plugin {0} v{1} by {2}",
"PluginUnloaded": "Unloaded plugin {0} v{1} by {2}",
"ServerLanguage": "Server language set to {0}",
"Unknown": "Unknown",
"UnknownCommand": "Unknown command: {0}",
"PlayerAddedToGroup": "Player '{0}' added to group: {1}",
"PlayerAlreadyHasPermission": "Player '{0}' already has permission '{1}'",
"PlayerDoesNotHavePermission": "Player '{0}' does not have permission '{1}'",
"PlayerNotFound": "Player '{0}' not found",
"PlayerGroups": "Player '{0}' groups",
"PlayerPermissions": "Player '{0}' permissions",
"PlayerPermissionGranted": "Player '{0}' granted permission '{1}'",
"PlayerPermissionRevoked": "Player '{0}' revoked permission '{1}'",
"PlayerRemovedFromGroup": "Player '{0}' removed from group '{1}'",
"PlayersFound": "Multiple players were found, please specify: {0}",
"Version": "Server is running [#ffb658]Oxide {0}[/#] and [#ee715c]{1} {2} ({3})[/#]",
"YouAreNotAdmin": "You are not an admin"
}

10
lang/en/WipeKits.json Normal file
View File

@ -0,0 +1,10 @@
{
"DayFormat": "<color=orange>{0}</color> day and <color=orange>{1}</color> hours",
"DaysFormat": "<color=orange>{0}</color> days and <color=orange>{1}</color> hours",
"HourFormat": "<color=orange>{0}</color> hour and <color=orange>{1}</color> minutes",
"HoursFormat": "<color=orange>{0}</color> hours and <color=orange>{1}</color> minutes",
"MinFormat": "<color=orange>{0}</color> minute and <color=orange>{1}</color> seconds",
"MinsFormat": "<color=orange>{0}</color> minutes and <color=orange>{1}</color> seconds",
"SecsFormat": "<color=orange>{0}</color> seconds",
"CantUse": "The server's just wiped! Try again in {0}"
}

View File

@ -0,0 +1,12 @@
[SERVER v1.0.20] Started as service
[SERVER v1.0.20] Running as service
[SERVER v1.0.20] Got Message: Ready
[SERVER v1.0.20] Got Message: Compile
[SERVER v1.0.20] Console: PermissionsManager.cs(299,24): warning CS0219: The variable `granted' is assigned but its value is never used
PermissionsManager.cs(353,20): warning CS0219: The variable `guiString' is assigned but its value is never used
PermissionsManager.cs(384,20): warning CS0219: The variable `guiString' is assigned but its value is never used
[SERVER v1.0.20] Got Message: Exit
[SERVER v1.0.20] Exit received.
[SERVER v1.0.20] Connection closed.
[SERVER v1.0.20] Shutdown

244
logs/oxide_2021-02-08.txt Normal file
View File

@ -0,0 +1,244 @@
17:35 [Info] Loading Oxide Core v2.0.3991...
17:35 [Info] Loading extensions...
17:35 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
17:35 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
17:35 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
17:35 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
17:35 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
17:35 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
17:35 [Info] Local compiler MD5: 0
17:35 [Info] Compiler MD5 hash did not match, downloading latest
17:35 [Info] Downloading Compiler.x86_x64 for .cs (C#) plugin compilation
17:35 [Info] Local MD5 hash did not match remote MD5 hash for Compiler.x86_x64, attempting download again
17:35 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
17:35 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
17:35 [Info] Using Covalence provider for game 'Rust'
17:35 [Info] Loading plugins...
17:35 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
17:35 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
17:44 [Info] IP address from Steam query: 0.0.0.0
18:16 [Info] Loading Oxide Core v2.0.3991...
18:16 [Info] Loading extensions...
18:16 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
18:16 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
18:16 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
18:16 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
18:16 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
18:16 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
18:16 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
18:16 [Info] Using Covalence provider for game 'Rust'
18:16 [Info] Loading plugins...
18:16 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
18:16 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
18:25 [Info] IP address from Steam query: 0.0.0.0
19:00 [Info] Loading Oxide Core v2.0.3991...
19:00 [Info] Loading extensions...
19:00 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
19:00 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
19:00 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
19:00 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
19:00 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
19:00 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:00 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:00 [Info] Using Covalence provider for game 'Rust'
19:00 [Info] Loading plugins...
19:00 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
19:00 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
19:09 [Info] IP address from Steam query: 0.0.0.0
19:17 [Info] Loading Oxide Core v2.0.3991...
19:17 [Info] Loading extensions...
19:17 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
19:17 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
19:17 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
19:17 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
19:17 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
19:17 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:17 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:17 [Info] Using Covalence provider for game 'Rust'
19:17 [Info] Loading plugins...
19:17 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
19:17 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
19:19 [Info] Loading Oxide Core v2.0.3991...
19:19 [Info] Loading extensions...
19:19 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
19:19 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
19:19 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
19:19 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
19:19 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
19:19 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:19 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:19 [Info] Using Covalence provider for game 'Rust'
19:19 [Info] Loading plugins...
19:19 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
19:19 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
19:29 [Info] IP address from Steam query: 0.0.0.0
19:34 [Info] Loading Oxide Core v2.0.3991...
19:34 [Info] Loading extensions...
19:34 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
19:34 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
19:34 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
19:34 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
19:34 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
19:34 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:34 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:34 [Info] Using Covalence provider for game 'Rust'
19:34 [Info] Loading plugins...
19:34 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
19:34 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
19:43 [Info] IP address from Steam query: 0.0.0.0
19:51 [Info] Loading Oxide Core v2.0.3991...
19:51 [Info] Loading extensions...
19:51 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
19:51 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
19:51 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
19:51 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
19:51 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
19:51 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:51 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:51 [Info] Using Covalence provider for game 'Rust'
19:51 [Info] Loading plugins...
19:51 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
19:51 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
19:52 [Info] Loading Oxide Core v2.0.3991...
19:52 [Info] Loading extensions...
19:52 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
19:52 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
19:52 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
19:52 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
19:52 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
19:52 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:52 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
19:52 [Info] Using Covalence provider for game 'Rust'
19:52 [Info] Loading plugins...
19:52 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
19:52 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
20:02 [Info] IP address from Steam query: 0.0.0.0
20:10 [Info] Loading Oxide Core v2.0.3991...
20:10 [Info] Loading extensions...
20:10 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
20:10 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
20:10 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
20:10 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
20:10 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
20:10 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:10 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:10 [Info] Using Covalence provider for game 'Rust'
20:10 [Info] Loading plugins...
20:10 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
20:10 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
20:19 [Info] IP address from Steam query: 0.0.0.0
20:25 [Info] Loading Oxide Core v2.0.3991...
20:25 [Info] Loading extensions...
20:25 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
20:25 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
20:25 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
20:25 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
20:25 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
20:25 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:25 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:25 [Info] Using Covalence provider for game 'Rust'
20:25 [Info] Loading plugins...
20:25 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
20:25 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
20:29 [Info] Loading Oxide Core v2.0.3991...
20:29 [Info] Loading extensions...
20:29 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
20:29 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
20:29 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
20:29 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
20:29 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
20:29 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:29 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:29 [Info] Using Covalence provider for game 'Rust'
20:29 [Info] Loading plugins...
20:29 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
20:29 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
20:39 [Info] IP address from Steam query: 0.0.0.0
20:43 [Info] Loading Oxide Core v2.0.3991...
20:43 [Info] Loading extensions...
20:43 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
20:43 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
20:43 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
20:43 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
20:43 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
20:43 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:43 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
20:43 [Info] Using Covalence provider for game 'Rust'
20:43 [Info] Loading plugins...
20:43 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
20:43 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
20:53 [Info] IP address from Steam query: 0.0.0.0
20:59 [Info] GatherManager was compiled successfully in 3410ms
20:59 [Warning] [Gathering Manager] New configuration file created.
20:59 [Warning] [Gathering Manager] Configuration file updated.
20:59 [Warning] Calling 'OnServerInitialized' on 'GatherManager v2.2.75' took 169ms
20:59 [Info] Loaded plugin Gathering Manager v2.2.75 by Mughisi
21:00 [Error] Oxide.Ext.Discord is referenced by DiscordAuth plugin but is not loaded! An appropriate include file needs to be saved to plugins\include\Ext.Discord.cs if this extension is not required.
21:00 [Info] CraftingController was compiled successfully in 3310ms
21:00 [Info] Loaded plugin Crafting Controller v3.2.2 by Whispers88
21:00 [Info] TimeOfDay was compiled successfully in 3578ms
21:00 [Info] Loaded plugin TimeOfDay v2.3.4 by FuJiCuRa
21:00 [Info] QuickSmelt was compiled successfully in 540ms
21:00 [Warning] Calling 'OnServerInitialized' on 'QuickSmelt v5.1.3' took 174ms
21:00 [Info] Loaded plugin Quick Smelt v5.1.3 by Iv Misticos
21:01 [Info] BetterLoot was compiled successfully in 691ms
21:01 [Info] [BetterLoot] No Blacklist found, creating new file...
21:01 [Info] [BetterLoot] Using '33' active of '35' supported containertypes
21:01 [Info] [BetterLoot] Exported 680 items to 'NamesList'
21:01 [Info] [BetterLoot] Updating internals ...
21:01 [Info] Loaded plugin BetterLoot v3.5.3 by Default
21:01 [Info] [BetterLoot] Removed 7 stacked LootContainer
21:01 [Info] [BetterLoot] Populated '3512' supported containers.
21:02 [Info] WipeKits was compiled successfully in 2774ms
21:02 [Warning] [Wipe Kits] Loading default configuration file...
21:02 [Info] Loaded plugin Wipe Kits v1.2.51 by Ryan
21:02 [Info] Kits was compiled successfully in 3011ms
21:02 [Info] Loaded plugin Kits v3.3.1 by Reneb
21:03 [Info] Unloaded plugin Kits v3.3.1 by Reneb
21:03 [Info] Loaded plugin Kits v3.3.1 by Reneb
21:04 [Warning] Calling 'Unload' on 'GatherManager v2.2.75' took 160ms
21:04 [Info] Unloaded plugin Gathering Manager v2.2.75 by Mughisi
21:04 [Info] Unloaded plugin Crafting Controller v3.2.2 by Whispers88
21:04 [Info] Unloaded plugin TimeOfDay v2.3.4 by FuJiCuRa
21:04 [Warning] Calling 'Unload' on 'QuickSmelt v5.1.3' took 155ms
21:04 [Info] Unloaded plugin Quick Smelt v5.1.3 by Iv Misticos
21:04 [Warning] Calling 'Unload' on 'BetterLoot v3.5.3' took 156ms
21:04 [Info] Unloaded plugin BetterLoot v3.5.3 by Default
21:04 [Info] Unloaded plugin Wipe Kits v1.2.51 by Ryan
21:04 [Info] Unloaded plugin Kits v3.3.1 by Reneb
21:04 [Info] Loading Oxide Core v2.0.3991...
21:04 [Info] Loading extensions...
21:04 [Info] Loaded extension CSharp v2.0.4041 by Oxide Team and Contributors
21:04 [Info] Loaded extension MySql v2.0.3760 by Oxide Team and Contributors
21:04 [Info] Loaded extension Rust v2.0.4907 by Oxide Team and Contributors
21:04 [Info] Loaded extension SQLite v2.0.3762 by Oxide Team and Contributors
21:04 [Info] Loaded extension Unity v2.0.3772 by Oxide Team and Contributors
21:04 [Info] Latest compiler MD5: 8ce6d27e7718e3d164766bba8833537a
21:04 [Info] Local compiler MD5: 8ce6d27e7718e3d164766bba8833537a
21:04 [Info] Using Covalence provider for game 'Rust'
21:04 [Info] Loading plugins...
21:04 [Info] Loaded plugin Rust v2.0.4907 by Oxide Team and Contributors
21:04 [Info] Loaded plugin Unity v2.0.3772 by Oxide Team and Contributors
21:04 [Error] Oxide.Ext.Discord is referenced by DiscordAuth plugin but is not loaded! An appropriate include file needs to be saved to plugins\include\Ext.Discord.cs if this extension is not required.
21:04 [Info] BetterLoot, CraftingController, GatherManager, Kits, QuickSmelt, TimeOfDay and WipeKits were compiled successfully in 0ms
21:04 [Info] Loaded plugin BetterLoot v3.5.3 by Default
21:04 [Info] Loaded plugin Crafting Controller v3.2.2 by Whispers88
21:04 [Info] Loaded plugin Gathering Manager v2.2.75 by Mughisi
21:04 [Info] Loaded plugin Kits v3.3.1 by Reneb
21:04 [Info] Loaded plugin Quick Smelt v5.1.3 by Iv Misticos
21:04 [Info] Loaded plugin TimeOfDay v2.3.4 by FuJiCuRa
21:04 [Info] Loaded plugin Wipe Kits v1.2.51 by Ryan
21:14 [Info] IP address from Steam query: 0.0.0.0
21:14 [Info] [BetterLoot] Using '33' active of '35' supported containertypes
21:14 [Info] [BetterLoot] Updating internals ...
21:14 [Warning] Calling 'OnServerInitialized' on 'GatherManager v2.2.75' took 133ms
21:14 [Warning] Calling 'OnServerInitialized' on 'QuickSmelt v5.1.3' took 133ms
21:14 [Info] [BetterLoot] No stacked LootContainer found.
21:14 [Info] [BetterLoot] Populated '800' supported containers.
22:15 [Info] The current crafting rate is 50%
22:17 [Info] Groups:
default, admin
22:17 [Info] Player 'Sick Prodigy(76561198106966240)' added to group: admin
22:22 [Info] PermissionsManager was compiled successfully in 3149ms
22:22 [Info] [PermissionsManager] Creating new config file.
22:22 [Info] Loaded plugin PermissionsManager v2.0.4 by Steenamaroo

23
oxide.config.json Normal file
View File

@ -0,0 +1,23 @@
{
"Options": {
"Modded": true,
"PluginWatchers": true,
"DefaultGroups": {
"Players": "default",
"Moderators": "moderate"
"Administrators": "admin"
},
"WebRequestIP": "0.0.0.0"
},
"OxideConsole": {
"Enabled": true,
"MinimalistMode": true,
"ShowStatusBar": true
},
"OxideRcon": {
"Enabled": false,
"Port": 25580,
"Password": "",
"ChatPrefix": "[Server Console]"
}
}

1813
plugins/AdminLogger.cs Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1357
plugins/Backpacks.cs Normal file

File diff suppressed because it is too large Load Diff

953
plugins/BetterChat.cs Normal file
View File

@ -0,0 +1,953 @@
using Oxide.Plugins.BetterChatExtensions;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;
using System;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
#if RUST
using Network;
using ConVar;
using Facepunch;
using Facepunch.Math;
using CompanionServer;
#endif
// TODO: Improve string usage by using stringbuilders
// TODO: Add "name" or "identifier" format for third-party plugins to obtain a formatted identifier
namespace Oxide.Plugins
{
[Info("Better Chat", "LaserHydra", "5.2.5")]
[Description("Allows to manage chat groups, customize colors and add titles.")]
internal class BetterChat : CovalencePlugin
{
#region Fields
private static BetterChat _instance;
private Configuration _config;
private List<ChatGroup> _chatGroups;
private Dictionary<Plugin, Func<IPlayer, string>> _thirdPartyTitles = new Dictionary<Plugin, Func<IPlayer, string>>();
private static readonly string[] _stringReplacements = new string[]
{
#if RUST || HURTWORLD || UNTURNED
"<b>", "</b>",
"<i>", "</i>",
"</size>",
"</color>"
#endif
};
private static readonly Regex[] _regexReplacements = new Regex[]
{
new Regex(@"<voffset=(?:.|\s)*?>", RegexOptions.Compiled),
#if RUST || HURTWORLD || UNTURNED
new Regex(@"<color=.+?>", RegexOptions.Compiled),
new Regex(@"<size=.+?>", RegexOptions.Compiled),
#elif REIGNOFKINGS || SEVENDAYSTODIE
new Regex(@"\[[\w\d]{6}\]", RegexOptions.Compiled),
#elif RUSTLEGACY
new Regex(@"\[color #[\w\d]{6}\]", RegexOptions.Compiled),
#elif TERRARIA
new Regex(@"\[c\/[\w\d]{6}:", RegexOptions.Compiled),
#endif
};
#endregion
#region Hooks
private void Loaded()
{
_instance = this;
LoadData(ref _chatGroups);
if (_chatGroups.Count == 0)
_chatGroups.Add(new ChatGroup("default"));
foreach (ChatGroup group in _chatGroups)
{
if (!permission.GroupExists(group.GroupName))
permission.CreateGroup(group.GroupName, string.Empty, 0);
}
SaveData(_chatGroups);
}
private void OnPluginUnloaded(Plugin plugin)
{
if (_thirdPartyTitles.ContainsKey(plugin))
_thirdPartyTitles.Remove(plugin);
}
#if RUST
private object OnPlayerChat(BasePlayer bplayer, string message, Chat.ChatChannel chatchannel)
{
IPlayer player = bplayer.IPlayer;
#else
private object OnUserChat(IPlayer player, string message)
{
#endif
if (message.Length > _instance._config.MaxMessageLength)
message = message.Substring(0, _instance._config.MaxMessageLength);
BetterChatMessage chatMessage = ChatGroup.FormatMessage(player, message);
if (chatMessage == null)
return null;
Dictionary<string, object> chatMessageDict = chatMessage.ToDictionary();
#if RUST
chatMessageDict.Add("ChatChannel", chatchannel);
#endif
foreach (Plugin plugin in plugins.GetAll())
{
object hookResult = plugin.CallHook("OnBetterChat", chatMessageDict);
if (hookResult is Dictionary<string, object>)
{
try
{
chatMessageDict = hookResult as Dictionary<string, object>;
}
catch (Exception e)
{
PrintError($"Failed to load modified OnBetterChat hook data from plugin '{plugin.Title} ({plugin.Version})':{Environment.NewLine}{e}");
continue;
}
}
else if (hookResult != null)
return null;
}
chatMessage = BetterChatMessage.FromDictionary(chatMessageDict);
switch (chatMessage.CancelOption)
{
case BetterChatMessage.CancelOptions.BetterChatOnly:
return null;
case BetterChatMessage.CancelOptions.BetterChatAndDefault:
return true;
}
var output = chatMessage.GetOutput();
#if RUST
switch (chatchannel)
{
case Chat.ChatChannel.Team:
RelationshipManager.PlayerTeam team = bplayer.Team;
if (team == null || team.members.Count == 0)
{
return true;
}
team.BroadcastTeamChat(bplayer.userID, player.Name, chatMessage.Message, chatMessage.UsernameSettings.Color);
List<Network.Connection> onlineMemberConnections = team.GetOnlineMemberConnections();
if (onlineMemberConnections != null)
{
ConsoleNetwork.SendClientCommand(onlineMemberConnections, "chat.add", new object[] { (int) chatchannel, player.Id, output.Chat });
}
break;
default:
foreach (BasePlayer p in BasePlayer.activePlayerList.Where(p => !chatMessage.BlockedReceivers.Contains(p.UserIDString)))
p.SendConsoleCommand("chat.add", new object[] { (int) chatchannel, player.Id, output.Chat });
break;
}
#else
foreach (IPlayer p in players.Connected.Where(p => !chatMessage.BlockedReceivers.Contains(p.Id)))
p.Message(output.Chat);
#endif
#if RUST
Puts($"[{chatchannel}] {output.Console}");
RCon.Broadcast(RCon.LogType.Chat, new Chat.ChatEntry
{
Channel = chatchannel,
Message = output.Console,
UserId = player.Id,
Username = player.Name,
Color = chatMessage.UsernameSettings.Color,
Time = Epoch.Current
});
#else
Puts(output.Console);
#endif
return true;
}
#endregion
#region API
private bool API_AddGroup(string group)
{
if (ChatGroup.Find(group) != null)
return false;
_chatGroups.Add(new ChatGroup(group));
SaveData(_chatGroups);
return true;
}
private List<JObject> API_GetAllGroups() => _chatGroups.ConvertAll(JObject.FromObject);
private List<JObject> API_GetUserGroups(IPlayer player) => ChatGroup.GetUserGroups(player).ConvertAll(JObject.FromObject);
private bool API_GroupExists(string group) => ChatGroup.Find(group) != null;
private ChatGroup.Field.SetValueResult? API_SetGroupField(string group, string field, string value) => ChatGroup.Find(group)?.SetField(field, value);
private Dictionary<string, object> API_GetGroupFields(string group) => ChatGroup.Find(group)?.GetFields() ?? new Dictionary<string, object>();
private Dictionary<string, object> API_GetMessageData(IPlayer player, string message) => ChatGroup.FormatMessage(player, message)?.ToDictionary();
private string API_GetFormattedUsername(IPlayer player)
{
var primary = ChatGroup.GetUserPrimaryGroup(player);
// Player has no groups - this should never happen
if (primary == null)
return player.Name;
return $"[#{primary.Username.GetUniversalColor()}][+{primary.Username.Size}]{player.Name}[/+][/#]";
}
private string API_GetFormattedMessage(IPlayer player, string message, bool console = false) => console ? ChatGroup.FormatMessage(player, message).GetOutput().Console : ChatGroup.FormatMessage(player, message).GetOutput().Chat;
private void API_RegisterThirdPartyTitle(Plugin plugin, Func<IPlayer, string> titleGetter) => _thirdPartyTitles[plugin] = titleGetter;
#endregion
#region Commands
[Command("chat"), Permission("betterchat.admin")]
private void CmdChat(IPlayer player, string cmd, string[] args)
{
cmd = player.LastCommand == CommandType.Console ? cmd : $"/{cmd}";
if (args.Length == 0)
{
player.Reply($"{cmd} group <add|remove|set|list>");
player.Reply($"{cmd} user <add|remove>");
return;
}
string argsStr = string.Join(" ", args);
var commands = new Dictionary<string, Action<string[]>>
{
["group add"] = a => {
if (a.Length != 1)
{
player.Reply($"Syntax: {cmd} group add <group>");
return;
}
string groupName = a[0].ToLower();
if (ChatGroup.Find(groupName) != null)
{
player.ReplyLang("Group Already Exists", new KeyValuePair<string, string>("group", groupName));
return;
}
ChatGroup group = new ChatGroup(groupName);
_chatGroups.Add(group);
if (!permission.GroupExists(group.GroupName))
permission.CreateGroup(group.GroupName, string.Empty, 0);
SaveData(_chatGroups);
player.ReplyLang("Group Added", new KeyValuePair<string, string>("group", groupName));
},
["group remove"] = a => {
if (a.Length != 1)
{
player.Reply($"Syntax: {cmd} group remove <group>");
return;
}
string groupName = a[0].ToLower();
ChatGroup group = ChatGroup.Find(groupName);
if (group == null)
{
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
return;
}
_chatGroups.Remove(group);
SaveData(_chatGroups);
player.ReplyLang("Group Removed", new KeyValuePair<string, string>("group", groupName));
},
["group set"] = a => {
if (a.Length != 3)
{
player.Reply($"Syntax: {cmd} group set <group> <field> <value>");
player.Reply($"Fields:{Environment.NewLine}{string.Join(", ", ChatGroup.Fields.Select(kvp => $"({kvp.Value.UserFriendyType}) {kvp.Key}").ToArray())}");
return;
}
string groupName = a[0].ToLower();
ChatGroup group = ChatGroup.Find(groupName);
if (group == null)
{
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
return;
}
string field = a[1];
string strValue = a[2];
switch (group.SetField(field, strValue))
{
case ChatGroup.Field.SetValueResult.Success:
SaveData(_chatGroups);
player.ReplyLang("Group Field Changed", new Dictionary<string, string> { ["group"] = group.GroupName, ["field"] = field, ["value"] = strValue });
break;
case ChatGroup.Field.SetValueResult.InvalidField:
player.ReplyLang("Invalid Field", new KeyValuePair<string, string>("field", field));
break;
case ChatGroup.Field.SetValueResult.InvalidValue:
player.ReplyLang("Invalid Value", new Dictionary<string, string> { ["field"] = field, ["value"] = strValue, ["type"] = ChatGroup.Fields[field].UserFriendyType });
break;
}
},
["group list"] = a =>
{
player.Reply(string.Join(", ", _chatGroups.Select(g => g.GroupName).ToArray()));
},
["group"] = a => player.Reply($"Syntax: {cmd} group <add|remove|set|list>"),
["user add"] = a => {
if (a.Length != 2)
{
player.Reply($"Syntax: {cmd} user add <username|id> <group>");
return;
}
string response;
IPlayer targetPlayer = FindPlayer(a[0], out response);
if (targetPlayer == null)
{
player.Reply(response);
return;
}
string groupName = a[1].ToLower();
ChatGroup group = ChatGroup.Find(groupName);
if (group == null)
{
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
return;
}
if (permission.UserHasGroup(targetPlayer.Id, groupName))
{
player.ReplyLang("Player Already In Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
return;
}
group.AddUser(targetPlayer);
player.ReplyLang("Added To Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
},
["user remove"] = a => {
if (a.Length != 2)
{
player.Reply($"Syntax: {cmd} user remove <username|id> <group>");
return;
}
string response;
IPlayer targetPlayer = FindPlayer(a[0], out response);
if (targetPlayer == null)
{
player.Reply(response);
return;
}
string groupName = a[1].ToLower();
ChatGroup group = ChatGroup.Find(groupName);
if (group == null)
{
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
return;
}
if (!permission.UserHasGroup(targetPlayer.Id, groupName))
{
player.ReplyLang("Player Not In Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
return;
}
group.RemoveUser(targetPlayer);
player.ReplyLang("Removed From Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
},
["user"] = a => player.Reply($"Syntax: {cmd} user <add|remove>"),
[string.Empty] = a =>
{
player.Reply($"{cmd} group <add|remove|set|list>");
player.Reply($"{cmd} user <add|remove>");
}
};
var command = commands.First(c => argsStr.ToLower().StartsWith(c.Key));
string remainingArgs = argsStr.Remove(0, command.Key.Length);
command.Value(remainingArgs.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToArray());
}
#endregion
#region Helper and Wrapper Methods
#region Player Lookup
private IPlayer FindPlayer(string nameOrID, out string response)
{
response = null;
if (IsConvertableTo<string, ulong>(nameOrID) && nameOrID.StartsWith("7656119") && nameOrID.Length == 17)
{
IPlayer result = players.All.ToList().Find((p) => p.Id == nameOrID);
if (result == null)
response = $"Could not find player with ID '{nameOrID}'";
return result;
}
List<IPlayer> foundPlayers = new List<IPlayer>();
foreach (IPlayer current in players.Connected)
{
if (current.Name.ToLower() == nameOrID.ToLower())
return current;
if (current.Name.ToLower().Contains(nameOrID.ToLower()))
foundPlayers.Add(current);
}
switch (foundPlayers.Count)
{
case 0:
response = $"Could not find player with name '{nameOrID}'";
break;
case 1:
return foundPlayers[0];
default:
string[] names = (from current in foundPlayers select current.Name).ToArray();
response = "Multiple matching players found: \n" + string.Join(", ", names);
break;
}
return null;
}
#endregion
#region Type Conversion
private bool IsConvertableTo<TSource, TResult>(TSource s)
{
TResult result;
return TryConvert(s, out result);
}
private bool TryConvert<TSource, TResult>(TSource s, out TResult c)
{
try
{
c = (TResult)Convert.ChangeType(s, typeof(TResult));
return true;
}
catch
{
c = default(TResult);
return false;
}
}
#endregion
#region Data
private void LoadData<T>(ref T data, string filename = null) => data = Core.Interface.Oxide.DataFileSystem.ReadObject<T>(filename ?? Name);
private void SaveData<T>(T data, string filename = null) => Core.Interface.Oxide.DataFileSystem.WriteObject(filename ?? Name, data);
#endregion
#region Formatting
private static string StripRichText(string text)
{
foreach (var replacement in _stringReplacements)
text = text.Replace(replacement, string.Empty);
foreach (var replacement in _regexReplacements)
text = replacement.Replace(text, string.Empty);
return Formatter.ToPlaintext(text);
}
#endregion
#region Message Wrapper
public static string GetMessage(string key, string id) => _instance.lang.GetMessage(key, _instance, id);
#endregion
#endregion
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Group Already Exists"] = "Group '{group}' already exists.",
["Group Does Not Exist"] = "Group '{group}' doesn't exist.",
["Group Field Changed"] = "Changed {field} to {value} for group '{group}'.",
["Group Added"] = "Successfully added group '{group}'.",
["Group Removed"] = "Successfully removed group '{group}'.",
["Invalid Field"] = "{field} is not a valid field. Type 'chat group set' to list all existing fields.",
["Invalid Value"] = "'{value}' is not a correct value for field '{field}'! Should be a '{type}'.",
["Player Already In Group"] = "{player} already is in group '{group}'.",
["Added To Group"] = "{player} was added to group '{group}'.",
["Player Not In Group"] = "{player} is not in group '{group}'.",
["Removed From Group"] = "{player} was removed from group '{group}'."
}, this);
}
#endregion
#region Configuration
protected override void LoadConfig()
{
base.LoadConfig();
_config = Config.ReadObject<Configuration>();
SaveConfig();
}
protected override void LoadDefaultConfig() => _config = new Configuration();
protected override void SaveConfig() => Config.WriteObject(_config);
private class Configuration
{
[JsonProperty("Maximal Titles")]
public int MaxTitles { get; set; } = 3;
[JsonProperty("Maximal Characters Per Message")]
public int MaxMessageLength { get; set; } = 128;
[JsonProperty("Reverse Title Order")]
public bool ReverseTitleOrder { get; set; } = false;
}
#endregion
#region Group Structures
public class BetterChatMessage
{
public IPlayer Player;
public string Username;
public string Message;
public List<string> Titles;
public string PrimaryGroup;
public ChatGroup.UsernameSettings UsernameSettings;
public ChatGroup.MessageSettings MessageSettings;
public ChatGroup.FormatSettings FormatSettings;
public List<string> BlockedReceivers = new List<string>();
public CancelOptions CancelOption;
public ChatGroup.FormatSettings GetOutput()
{
ChatGroup.FormatSettings output = new ChatGroup.FormatSettings();
Dictionary<string, string> replacements = new Dictionary<string, string>
{
["Title"] = string.Join(" ", Titles.ToArray()),
["Username"] = $"[#{UsernameSettings.GetUniversalColor()}][+{UsernameSettings.Size}]{Username}[/+][/#]",
["Group"] = PrimaryGroup,
["Message"] = $"[#{MessageSettings.GetUniversalColor()}][+{MessageSettings.Size}]{Message}[/+][/#]",
["ID"] = Player.Id,
["Time"] = DateTime.Now.TimeOfDay.ToString(),
["Date"] = DateTime.Now.ToString()
};
output.Chat = FormatSettings.Chat;
output.Console = FormatSettings.Console;
foreach (var replacement in replacements)
{
output.Console = StripRichText(output.Console.Replace($"{{{replacement.Key}}}", replacement.Value));
output.Chat = _instance.covalence.FormatText(output.Chat.Replace($"{{{replacement.Key}}}", replacement.Value));
}
if (output.Chat.StartsWith(" "))
output.Chat = output.Chat.Remove(0, 1);
if (output.Console.StartsWith(" "))
output.Console = output.Console.Remove(0, 1);
return output;
}
public static BetterChatMessage FromDictionary(Dictionary<string, object> dictionary)
{
var usernameSettings = dictionary[nameof(UsernameSettings)] as Dictionary<string, object>;
var messageSettings = dictionary[nameof(MessageSettings)] as Dictionary<string, object>;
var formatSettings = dictionary[nameof(FormatSettings)] as Dictionary<string, object>;
return new BetterChatMessage
{
Player = dictionary[nameof(Player)] as IPlayer,
Message = dictionary[nameof(Message)] as string,
Username = dictionary[nameof(Username)] as string,
Titles = dictionary[nameof(Titles)] as List<string>,
PrimaryGroup = dictionary[nameof(PrimaryGroup)] as string,
BlockedReceivers = dictionary[nameof(BlockedReceivers)] as List<string>,
UsernameSettings = new ChatGroup.UsernameSettings
{
Color = usernameSettings[nameof(ChatGroup.UsernameSettings.Color)] as string,
Size = (int)usernameSettings[nameof(ChatGroup.UsernameSettings.Size)]
},
MessageSettings = new ChatGroup.MessageSettings
{
Color = messageSettings[nameof(ChatGroup.MessageSettings.Color)] as string,
Size = (int)messageSettings[nameof(ChatGroup.MessageSettings.Size)]
},
FormatSettings = new ChatGroup.FormatSettings
{
Chat = formatSettings[nameof(ChatGroup.FormatSettings.Chat)] as string,
Console = formatSettings[nameof(ChatGroup.FormatSettings.Console)] as string
},
CancelOption = (CancelOptions) dictionary[nameof(CancelOption)]
};
}
public Dictionary<string, object> ToDictionary() => new Dictionary<string, object>
{
[nameof(Player)] = Player,
[nameof(Message)] = Message,
[nameof(Username)] = Username,
[nameof(Titles)] = Titles,
[nameof(PrimaryGroup)] = PrimaryGroup,
[nameof(BlockedReceivers)] = BlockedReceivers,
[nameof(UsernameSettings)] = new Dictionary<string, object>
{
[nameof(ChatGroup.UsernameSettings.Color)] = UsernameSettings.Color,
[nameof(ChatGroup.UsernameSettings.Size)] = UsernameSettings.Size
},
[nameof(MessageSettings)] = new Dictionary<string, object>
{
[nameof(ChatGroup.MessageSettings.Color)] = MessageSettings.Color,
[nameof(ChatGroup.MessageSettings.Size)] = MessageSettings.Size
},
[nameof(FormatSettings)] = new Dictionary<string, object>
{
[nameof(ChatGroup.FormatSettings.Chat)] = FormatSettings.Chat,
[nameof(ChatGroup.FormatSettings.Console)] = FormatSettings.Console
},
[nameof(CancelOption)] = CancelOption
};
public enum CancelOptions
{
None = 0,
BetterChatOnly = 1,
BetterChatAndDefault = 2
}
}
public class ChatGroup
{
private static readonly ChatGroup _fallbackGroup = new ChatGroup("default");
#if RUST
private static readonly ChatGroup _rustDeveloperGroup = new ChatGroup("rust_developer")
{
Priority = 100,
Title =
{
Text = "[Rust Developer]",
Color = "#ffaa55"
}
};
#endif
public string GroupName;
public int Priority = 0;
public TitleSettings Title = new TitleSettings();
public UsernameSettings Username = new UsernameSettings();
public MessageSettings Message = new MessageSettings();
public FormatSettings Format = new FormatSettings();
public ChatGroup(string name)
{
GroupName = name;
Title = new TitleSettings(name);
}
public static readonly Dictionary<string, Field> Fields = new Dictionary<string, Field>(StringComparer.InvariantCultureIgnoreCase)
{
["Priority"] = new Field(g => g.Priority, (g, v) => g.Priority = int.Parse(v), "number"),
["Title"] = new Field(g => g.Title.Text, (g, v) => g.Title.Text = v, "text"),
["TitleColor"] = new Field(g => g.Title.Color, (g, v) => g.Title.Color = v, "color"),
["TitleSize"] = new Field(g => g.Title.Size, (g, v) => g.Title.Size = int.Parse(v), "number"),
["TitleHidden"] = new Field(g => g.Title.Hidden, (g, v) => g.Title.Hidden = bool.Parse(v), "true/false"),
["TitleHiddenIfNotPrimary"] = new Field(g => g.Title.HiddenIfNotPrimary, (g, v) => g.Title.HiddenIfNotPrimary = bool.Parse(v), "true/false"),
["UsernameColor"] = new Field(g => g.Username.Color, (g, v) => g.Username.Color = v, "color"),
["UsernameSize"] = new Field(g => g.Username.Size, (g, v) => g.Username.Size = int.Parse(v), "number"),
["MessageColor"] = new Field(g => g.Message.Color, (g, v) => g.Message.Color = v, "color"),
["MessageSize"] = new Field(g => g.Message.Size, (g, v) => g.Message.Size = int.Parse(v), "number"),
["ChatFormat"] = new Field(g => g.Format.Chat, (g, v) => g.Format.Chat = v, "text"),
["ConsoleFormat"] = new Field(g => g.Format.Console, (g, v) => g.Format.Console = v, "text")
};
public static ChatGroup Find(string name) => _instance._chatGroups.Find(g => g.GroupName == name);
public static List<ChatGroup> GetUserGroups(IPlayer player)
{
string[] oxideGroups = _instance.permission.GetUserGroups(player.Id);
var groups = _instance._chatGroups.Where(g => oxideGroups.Any(name => g.GroupName.ToLower() == name)).ToList();
#if RUST
BasePlayer bPlayer = BasePlayer.Find(player.Id);
if (bPlayer?.IsDeveloper ?? false)
groups.Add(_rustDeveloperGroup);
#endif
return groups;
}
public static ChatGroup GetUserPrimaryGroup(IPlayer player)
{
List<ChatGroup> groups = GetUserGroups(player);
ChatGroup primary = null;
foreach (ChatGroup group in groups)
if (primary == null || group.Priority < primary.Priority)
primary = group;
return primary;
}
public static BetterChatMessage FormatMessage(IPlayer player, string message)
{
ChatGroup primary = GetUserPrimaryGroup(player);
List<ChatGroup> groups = GetUserGroups(player);
if (primary == null)
{
_instance.PrintWarning($"{player.Name} ({player.Id}) does not seem to be in any BetterChat group - falling back to plugin's default group! This should never happen! Please make sure you have a group called 'default'.");
primary = _fallbackGroup;
groups.Add(primary);
}
groups.Sort((a, b) => b.Priority.CompareTo(a.Priority));
var titles = (from g in groups
where !g.Title.Hidden && !(g.Title.HiddenIfNotPrimary && primary != g)
select $"[#{g.Title.GetUniversalColor()}][+{g.Title.Size}]{g.Title.Text}[/+][/#]")
.ToList();
titles = titles.GetRange(0, Math.Min(_instance._config.MaxTitles, titles.Count));
if (_instance._config.ReverseTitleOrder)
{
titles.Reverse();
}
foreach (var thirdPartyTitle in _instance._thirdPartyTitles)
{
try
{
string title = thirdPartyTitle.Value(player);
if (!string.IsNullOrEmpty(title))
titles.Add(title);
}
catch (Exception ex)
{
_instance.PrintError($"Error when trying to get third-party title from plugin '{thirdPartyTitle.Key}'{Environment.NewLine}{ex}");
}
}
return new BetterChatMessage
{
Player = player,
Username = StripRichText(player.Name),
Message = StripRichText(message),
Titles = titles,
PrimaryGroup = primary.GroupName,
UsernameSettings = primary.Username,
MessageSettings = primary.Message,
FormatSettings = primary.Format
};
}
public void AddUser(IPlayer player) => _instance.permission.AddUserGroup(player.Id, GroupName);
public void RemoveUser(IPlayer player) => _instance.permission.RemoveUserGroup(player.Id, GroupName);
public Field.SetValueResult SetField(string field, string value)
{
if (!Fields.ContainsKey(field))
return Field.SetValueResult.InvalidField;
try
{
Fields[field].Setter(this, value);
}
catch (FormatException)
{
return Field.SetValueResult.InvalidValue;
}
return Field.SetValueResult.Success;
}
public Dictionary<string, object> GetFields() => Fields.ToDictionary(field => field.Key, field => field.Value.Getter(this));
public override int GetHashCode() => GroupName.GetHashCode();
public class TitleSettings
{
public string Text = "[Player]";
public string Color = "#55aaff";
public int Size = 15;
public bool Hidden = false;
public bool HiddenIfNotPrimary = false;
public string GetUniversalColor() => Color.StartsWith("#") ? Color.Substring(1) : Color;
public TitleSettings(string groupName)
{
if (groupName != "default" && groupName != null)
Text = $"[{groupName}]";
}
public TitleSettings()
{
}
}
public class UsernameSettings
{
public string Color = "#55aaff";
public int Size = 15;
public string GetUniversalColor() => Color.StartsWith("#") ? Color.Substring(1) : Color;
}
public class MessageSettings
{
public string Color = "white";
public int Size = 15;
public string GetUniversalColor() => Color.StartsWith("#") ? Color.Substring(1) : Color;
}
public class FormatSettings
{
public string Chat = "{Title} {Username}: {Message}";
public string Console = "{Title} {Username}: {Message}";
}
public class Field
{
public Func<ChatGroup, object> Getter { get; }
public Action<ChatGroup, string> Setter { get; }
public string UserFriendyType { get; }
public enum SetValueResult
{
Success,
InvalidField,
InvalidValue
}
public Field(Func<ChatGroup, object> getter, Action<ChatGroup, string> setter, string userFriendyType)
{
Getter = getter;
Setter = setter;
UserFriendyType = userFriendyType;
}
}
}
#endregion
}
}
#region Extension Methods
namespace Oxide.Plugins.BetterChatExtensions
{
internal static class IPlayerExtensions
{
public static void ReplyLang(this IPlayer player, string key, Dictionary<string, string> replacements = null)
{
string message = BetterChat.GetMessage(key, player.Id);
if (replacements != null)
foreach (var replacement in replacements)
message = message.Replace($"{{{replacement.Key}}}", replacement.Value);
replacements = null;
player.Reply(message);
}
public static void ReplyLang(this IPlayer player, string key, KeyValuePair<string, string> replacement)
{
string message = BetterChat.GetMessage(key, player.Id);
message = message.Replace($"{{{replacement.Key}}}", replacement.Value);
player.Reply(message);
}
}
}
#endregion

880
plugins/BetterLoot.cs Normal file
View File

@ -0,0 +1,880 @@
using Rust;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using UnityEngine;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core.Configuration;
using Random = System.Random;
using Oxide.Core;
using Oxide.Core.Plugins;
using Facepunch.Extend;
namespace Oxide.Plugins
{
[Info("BetterLoot", "Default", "3.5.3")]
[Description("A light loot container modification system")]
public class BetterLoot : RustPlugin
{
[PluginReference]
Plugin CustomLootSpawns;
static BetterLoot bl = null;
bool Changed = true;
int populatedContainers;
StoredExportNames storedExportNames = new StoredExportNames();
StoredBlacklist storedBlacklist = new StoredBlacklist();
Random rng = new Random();
bool initialized = false;
Dictionary<string, List<string>[]> Items = new Dictionary<string, List<string>[]>();
Dictionary<string, List<string>[]> Blueprints = new Dictionary<string, List<string>[]>();
Dictionary<string, int[]> itemWeights = new Dictionary<string, int[]>();
Dictionary<string, int[]> blueprintWeights = new Dictionary<string, int[]>();
Dictionary<string, int> totalItemWeight = new Dictionary<string, int>();
Dictionary<string, int> totalBlueprintWeight = new Dictionary<string, int>();
DynamicConfigFile lootTable;
DynamicConfigFile getFile(string file) => Interface.Oxide.DataFileSystem.GetDatafile($"{this.Title}/{file}");
bool chkFile(string file) => Interface.Oxide.DataFileSystem.ExistsDatafile($"{this.Title}/{file}");
Dictionary<string, object> lootTables = null;
static List<object> lootPrefabDefaults()
{
var dp = new List<object>()
{
"assets/bundled/prefabs/radtown/crate_basic.prefab",
"assets/bundled/prefabs/radtown/crate_elite.prefab",
"assets/bundled/prefabs/radtown/crate_mine.prefab",
"assets/bundled/prefabs/radtown/crate_normal.prefab",
"assets/bundled/prefabs/radtown/crate_normal_2.prefab",
"assets/bundled/prefabs/radtown/crate_normal_2_food.prefab",
"assets/bundled/prefabs/radtown/crate_normal_2_medical.prefab",
"assets/bundled/prefabs/radtown/crate_tools.prefab",
"assets/bundled/prefabs/radtown/crate_underwater_advanced.prefab",
"assets/bundled/prefabs/radtown/crate_underwater_basic.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm ammo.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm c4.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm construction resources.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm construction tools.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm food.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm medical.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm res.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm tier1 lootbox.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm tier2 lootbox.prefab",
"assets/bundled/prefabs/radtown/dmloot/dm tier3 lootbox.prefab",
"assets/bundled/prefabs/radtown/vehicle_parts.prefab",
"assets/bundled/prefabs/radtown/foodbox.prefab",
"assets/bundled/prefabs/radtown/loot_barrel_1.prefab",
"assets/bundled/prefabs/radtown/loot_barrel_2.prefab",
"assets/bundled/prefabs/autospawn/resource/loot/loot-barrel-1.prefab",
"assets/bundled/prefabs/autospawn/resource/loot/loot-barrel-2.prefab",
"assets/bundled/prefabs/autospawn/resource/loot/trash-pile-1.prefab",
"assets/bundled/prefabs/radtown/loot_trash.prefab",
"assets/bundled/prefabs/radtown/minecart.prefab",
"assets/bundled/prefabs/radtown/oil_barrel.prefab",
"assets/prefabs/npc/m2bradley/bradley_crate.prefab",
"assets/prefabs/npc/patrol helicopter/heli_crate.prefab",
"assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab",
"assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate_oilrig.prefab",
"assets/prefabs/misc/supply drop/supply_drop.prefab",
//"assets/prefabs/npc/scientist/scientist_corpse.prefab"
};
return dp;
}
void LoadAllContainers()
{
try { lootTable = getFile("LootTables"); }
catch (JsonReaderException e)
{
PrintWarning($"JSON error in 'LootTables' > Line: {e.LineNumber} | {e.Path}");
Interface.GetMod().UnloadPlugin(this.Title);
return;
}
lootTables = new Dictionary<string, object>();
lootTables = lootTable["LootTables"] as Dictionary<string, object>;
if (lootTables == null)
lootTables = new Dictionary<string, object>();
bool wasAdded = false;
foreach (var lootPrefab in lootPrefabsToUse)
{
if (!lootTables.ContainsKey((string)lootPrefab))
{
var loot = GameManager.server.FindPrefab((string)lootPrefab)?.GetComponent<LootContainer>();
if (loot == null)
continue;
var container = new Dictionary<string, object>();
container.Add("Enabled", !((string)lootPrefab).Contains("bradley_crate") && !((string)lootPrefab).Contains("heli_crate"));
container.Add("Scrap", loot.scrapAmount);
int slots = 0;
if (loot.LootSpawnSlots.Length > 0)
{
LootContainer.LootSpawnSlot[] lootSpawnSlots = loot.LootSpawnSlots;
for (int i = 0; i < lootSpawnSlots.Length; i++)
slots += lootSpawnSlots[i].numberToSpawn;
}
else
slots = loot.maxDefinitionsToSpawn;
container.Add("ItemsMin", slots);
container.Add("ItemsMax", slots);
container.Add("MaxBPs", 1);
var itemList = new Dictionary<string, object>();
if (loot.lootDefinition != null)
GetLootSpawn(loot.lootDefinition, ref itemList);
else if (loot.LootSpawnSlots.Length > 0)
{
LootContainer.LootSpawnSlot[] lootSpawnSlots = loot.LootSpawnSlots;
foreach (var lootSpawnSlot in lootSpawnSlots)
{
GetLootSpawn(lootSpawnSlot.definition, ref itemList);
}
}
container.Add("ItemList", itemList);
lootTables.Add((string)lootPrefab, container);
wasAdded = true;
}
}
if (wasAdded)
{
lootTable.Set("LootTables", lootTables);
lootTable.Save();
}
wasAdded = false;
bool wasRemoved = false;
int activeTypes = 0;
foreach (var lootTable in lootTables.ToList())
{
var loot = GameManager.server.FindPrefab(lootTable.Key)?.GetComponent<LootContainer>();
if (loot == null)
{
lootTables.Remove(lootTable.Key);
wasRemoved = true;
continue;
}
var container = lootTable.Value as Dictionary<string, object>;
if (!container.ContainsKey("Enabled"))
{
container.Add("Enabled", true);
wasAdded = true;
}
if ((bool)container["Enabled"])
activeTypes++;
if (!container.ContainsKey("Scrap"))
{
container.Add("Scrap", loot.scrapAmount);
wasAdded = true;
}
int slots = 0;
if (loot.LootSpawnSlots.Length > 0)
{
LootContainer.LootSpawnSlot[] lootSpawnSlots = loot.LootSpawnSlots;
for (int i = 0; i < lootSpawnSlots.Length; i++)
slots += lootSpawnSlots[i].numberToSpawn;
}
else
slots = loot.maxDefinitionsToSpawn;
if (!container.ContainsKey("MaxBPs"))
{
container.Add("MaxBPs", 1);
wasAdded = true;
}
if (!container.ContainsKey("ItemsMin"))
{
container.Add("ItemsMin", slots);
wasAdded = true;
}
if (!container.ContainsKey("ItemsMax"))
{
container.Add("ItemsMax", slots);
wasAdded = true;
}
if (!container.ContainsKey("ItemsMax"))
{
container.Add("ItemsMax", slots);
wasAdded = true;
}
if (!container.ContainsKey("ItemList"))
{
var itemList = new Dictionary<string, object>();
if (loot.lootDefinition != null)
GetLootSpawn(loot.lootDefinition, ref itemList);
else if (loot.LootSpawnSlots.Length > 0)
{
LootContainer.LootSpawnSlot[] lootSpawnSlots = loot.LootSpawnSlots;
for (int i = 0; i < lootSpawnSlots.Length; i++)
{
LootContainer.LootSpawnSlot lootSpawnSlot = lootSpawnSlots[i];
GetLootSpawn(lootSpawnSlot.definition, ref itemList);
}
}
container.Add("ItemList", itemList);
wasAdded = true;
}
Items.Add(lootTable.Key, new List<string>[5]);
Blueprints.Add(lootTable.Key, new List<string>[5]);
for (var i = 0; i < 5; ++i)
{
Items[lootTable.Key][i] = new List<string>();
Blueprints[lootTable.Key][i] = new List<string>();
}
foreach (var itemEntry in container["ItemList"] as Dictionary<string, object>)
{
bool isBP = itemEntry.Key.EndsWith(".blueprint") ? true : false;
var def = ItemManager.FindItemDefinition(itemEntry.Key.Replace(".blueprint", ""));
if (def != null)
{
if (isBP && def.Blueprint != null && def.Blueprint.isResearchable)
{
int index = (int)def.rarity;
if (!Blueprints[lootTable.Key][index].Contains(def.shortname))
Blueprints[lootTable.Key][index].Add(def.shortname);
}
else
{
int index = 0;
object indexoverride;
if (rarityItemOverride.TryGetValue(def.shortname, out indexoverride))
index = Convert.ToInt32(indexoverride);
else
index = (int)def.rarity;
if (!Items[lootTable.Key][index].Contains(def.shortname))
Items[lootTable.Key][index].Add(def.shortname);
}
}
}
totalItemWeight.Add(lootTable.Key, 0);
totalBlueprintWeight.Add(lootTable.Key, 0);
itemWeights.Add(lootTable.Key, new int[5]);
blueprintWeights.Add(lootTable.Key, new int[5]);
for (var i = 0; i < 5; ++i)
{
totalItemWeight[lootTable.Key] += (itemWeights[lootTable.Key][i] = ItemWeight(baseItemRarity, i) * Items[lootTable.Key][i].Count);
totalBlueprintWeight[lootTable.Key] += (blueprintWeights[lootTable.Key][i] = ItemWeight(baseItemRarity, i) * Blueprints[lootTable.Key][i].Count);
}
}
if (wasAdded || wasRemoved)
{
lootTable.Set("LootTables", lootTables);
lootTable.Save();
}
lootTable.Clear();
Puts($"Using '{activeTypes}' active of '{lootTables.Count}' supported containertypes");
}
int ItemWeight(double baseRarity, int index) { return (int)(Math.Pow(baseRarity, 4 - index) * 1000); }
void GetLootSpawn(LootSpawn lootSpawn, ref Dictionary<string, object> items)
{
if (lootSpawn.subSpawn != null && lootSpawn.subSpawn.Length > 0)
{
foreach (var entry in lootSpawn.subSpawn)
GetLootSpawn(entry.category, ref items);
return;
}
if (lootSpawn.items != null && lootSpawn.items.Length > 0)
{
foreach (var amount in lootSpawn.items)
{
object options = GetAmounts(amount, 1);
string itemName = amount.itemDef.shortname;
if (amount.itemDef.spawnAsBlueprint)
itemName += ".blueprint";
if (!items.ContainsKey(itemName))
items.Add(itemName, options);
}
}
}
object GetAmounts(ItemAmount amount, int mul = 1)
{
if (amount.itemDef.isWearable || (amount.itemDef.condition.enabled && amount.itemDef.GetComponent<ItemModDeployable>() == null))
mul = 1;
object options = new Dictionary<string, object>
{
["Min"] = (int)amount.amount * mul,
["Max"] = ((ItemAmountRanged)amount).maxAmount > 0f &&
((ItemAmountRanged)amount).maxAmount > amount.amount
? (int)((ItemAmountRanged)amount).maxAmount * mul
: (int)amount.amount * mul,
};
return options;
}
static Dictionary<string, object> defaultItemOverride()
{
var dp = new Dictionary<string, object>();
dp.Add("autoturret", 4);
dp.Add("lmg.m249", 4);
dp.Add("targeting.computer", 3);
return dp;
}
double baseItemRarity;
double blueprintProbability;
bool removeStackedContainers;
bool listUpdatesOnLoaded;
double hammerLootCycleTime;
int lootMultiplier;
int scrapMultiplier;
bool enableHammerLootCycle;
Dictionary<string, object> rarityItemOverride = null;
List<object> lootPrefabsToUse = null;
object GetConfig(string menu, string datavalue, object defaultValue)
{
var data = Config[menu] as Dictionary<string, object>;
if (data == null)
{
data = new Dictionary<string, object>();
Config[menu] = data;
Changed = true;
}
object value;
if (data.TryGetValue(datavalue, out value)) return value;
value = defaultValue;
data[datavalue] = value;
Changed = true;
return value;
}
void LoadVariables()
{
baseItemRarity = 2;
rarityItemOverride = (Dictionary<string, object>)GetConfig("Rarity", "Override", defaultItemOverride());
lootPrefabsToUse = (List<object>)GetConfig("Generic", "WatchedPrefabs", lootPrefabDefaults());
listUpdatesOnLoaded = Convert.ToBoolean(GetConfig("Generic", "listUpdatesOnLoaded", true));
removeStackedContainers = Convert.ToBoolean(GetConfig("Generic", "removeStackedContainers", true));
blueprintProbability = Convert.ToDouble(GetConfig("Generic", "blueprintProbability", 0.11));
hammerLootCycleTime = Convert.ToDouble(GetConfig("Loot", "hammerLootCycleTime", 3));
lootMultiplier = Convert.ToInt32(GetConfig("Loot", "lootMultiplier", 1));
scrapMultiplier = Convert.ToInt32(GetConfig("Loot", "scrapMultiplier", 1));
enableHammerLootCycle = Convert.ToBoolean(GetConfig("Loot", "enableHammerLootCycle", false));
if (!Changed) return;
SaveConfig();
Changed = false;
}
class StoredBlacklist
{
public List<string> ItemList = new List<string>();
public StoredBlacklist()
{
}
}
void LoadBlacklist()
{
storedBlacklist = Interface.GetMod().DataFileSystem.ReadObject<StoredBlacklist>("BetterLoot\\Blacklist");
if (storedBlacklist.ItemList.Count == 0)
{
Puts("No Blacklist found, creating new file...");
storedBlacklist = new StoredBlacklist();
storedBlacklist.ItemList.Add("flare");
Interface.GetMod().DataFileSystem.WriteObject("BetterLoot\\Blacklist", storedBlacklist);
return;
}
}
void SaveBlacklist() => Interface.GetMod().DataFileSystem.WriteObject("BetterLoot\\Blacklist", storedBlacklist);
protected override void LoadDefaultConfig()
{
Config.Clear();
LoadVariables();
}
void Init()
{
LoadVariables();
LoadBlacklist();
bl = this;
}
void OnServerInitialized()
{
ItemManager.Initialize();
LoadAllContainers();
UpdateInternals(listUpdatesOnLoaded);
}
//void OnLootEntity(BasePlayer player, BaseEntity target)
//{
//Puts($"{player.displayName} looted {target.PrefabName}");
//}
void Unload()
{
var gameObjects = UnityEngine.Object.FindObjectsOfType<HammerHitLootCycle>().ToList();
if (gameObjects.Count > 0)
{
foreach (var objects in gameObjects)
{
UnityEngine.Object.Destroy(objects);
}
}
}
void UpdateInternals(bool doLog)
{
SaveExportNames();
if (Changed)
{
SaveConfig();
Changed = false;
}
Puts("Updating internals ...");
populatedContainers = 0;
NextTick(() =>
{
if (removeStackedContainers)
FixLoot();
foreach (var container in BaseNetworkable.serverEntities.Where(p => p != null && p.GetComponent<BaseEntity>() != null && p is LootContainer).Cast<LootContainer>().ToList())
{
if (container == null)
continue;
if (CustomLootSpawns != null && (CustomLootSpawns && (bool)CustomLootSpawns?.Call("IsLootBox", container.GetComponent<BaseEntity>())))
continue;
if (PopulateContainer(container))
populatedContainers++;
}
Puts($"Populated '{populatedContainers}' supported containers.");
initialized = true;
populatedContainers = 0;
ItemManager.DoRemoves();
});
}
void FixLoot()
{
var spawns = Resources.FindObjectsOfTypeAll<LootContainer>()
.Where(c => c.isActiveAndEnabled).
OrderBy(c => c.transform.position.x).ThenBy(c => c.transform.position.z).ThenBy(c => c.transform.position.z)
.ToList();
var count = spawns.Count();
var racelimit = count * count;
var antirace = 0;
var deleted = 0;
for (var i = 0; i < count; i++)
{
var box = spawns[i];
var pos = new Vector2(box.transform.position.x, box.transform.position.z);
if (++antirace > racelimit)
{
return;
}
var next = i + 1;
while (next < count)
{
var box2 = spawns[next];
var pos2 = new Vector2(box2.transform.position.x, box2.transform.position.z);
var distance = Vector2.Distance(pos, pos2);
if (++antirace > racelimit)
{
return;
}
if (distance < 0.25f)
{
spawns.RemoveAt(next);
count--;
(box2 as BaseEntity).KillMessage();
deleted++;
}
else break;
}
}
if (deleted > 0)
Puts($"Removed {deleted} stacked LootContainer");
else
Puts($"No stacked LootContainer found.");
ItemManager.DoRemoves();
}
bool PopulateContainer(LootContainer container)
{
Dictionary<string, object> con;
object containerobj;
if (!lootTables.TryGetValue(container.PrefabName, out containerobj))
return false;
con = containerobj as Dictionary<string, object>;
if (!(bool)con["Enabled"])
return false;
var lootitemcount = (con["ItemList"] as Dictionary<string, object>)?.Count();
int itemCount = Mathf.RoundToInt(UnityEngine.Random.Range(Convert.ToSingle(Mathf.Min((int)con["ItemsMin"], (int)con["ItemsMax"])) * 100f, Convert.ToSingle(Mathf.Max((int)con["ItemsMin"], (int)con["ItemsMax"])) * 100f) / 100f);
if (lootitemcount > 0 && itemCount > lootitemcount && lootitemcount < 36)
itemCount = (int)lootitemcount;
if (container.inventory == null)
{
container.inventory = new ItemContainer();
container.inventory.ServerInitialize(null, 36);
container.inventory.GiveUID();
}
else
{
while (container.inventory.itemList.Count > 0)
{
var item = container.inventory.itemList[0];
item.RemoveFromContainer();
item.Remove(0f);
}
container.inventory.capacity = 36;
}
var items = new List<Item>();
var itemNames = new List<string>();
var itemBlueprints = new List<int>();
var maxRetry = 10;
for (int i = 0; i < itemCount; ++i)
{
if (maxRetry == 0)
{
break;
}
var item = MightyRNG(container.PrefabName, itemCount, (bool)(itemBlueprints.Count >= (int)con["MaxBPs"]));
if (item == null)
{
--maxRetry;
--i;
continue;
}
if (itemNames.Contains(item.info.shortname) || (item.IsBlueprint() && itemBlueprints.Contains(item.blueprintTarget)))
{
item.Remove(0f);
--maxRetry;
--i;
continue;
}
else
if (item.IsBlueprint())
itemBlueprints.Add(item.blueprintTarget);
else
itemNames.Add(item.info.shortname);
items.Add(item);
if (storedBlacklist.ItemList.Contains(item.info.shortname))
{
items.Remove(item);
}
}
foreach (var item in items.Where(x => x != null && x.IsValid()))
item.MoveToContainer(container.inventory, -1, false);
if ((int)con["Scrap"] > 0)
{
int scrapCount = (int)con["Scrap"];
Item item = ItemManager.Create(ItemManager.FindItemDefinition("scrap"), scrapCount * scrapMultiplier, 0uL);
item.MoveToContainer(container.inventory, -1, false);
}
container.inventory.capacity = container.inventory.itemList.Count;
container.inventory.MarkDirty();
container.SendNetworkUpdate();
populatedContainers++;
return true;
}
Item MightyRNG(string type, int itemCount, bool blockBPs = false)
{
bool asBP = rng.NextDouble() < blueprintProbability && !blockBPs;
List<string> selectFrom;
int limit = 0;
string itemName;
Item item;
int maxRetry = 10 * itemCount;
do
{
selectFrom = null;
item = null;
if (asBP)
{
var r = rng.Next(totalBlueprintWeight[type]);
for (var i = 0; i < 5; ++i)
{
limit += blueprintWeights[type][i];
if (r < limit)
{
selectFrom = Blueprints[type][i];
break;
}
}
}
else
{
var r = rng.Next(totalItemWeight[type]);
for (var i = 0; i < 5; ++i)
{
limit += itemWeights[type][i];
if (r < limit)
{
selectFrom = Items[type][i];
break;
}
}
}
if (selectFrom == null)
{
if (--maxRetry <= 0)
break;
continue;
}
itemName = selectFrom[rng.Next(0, selectFrom.Count)];
ItemDefinition itemDef = ItemManager.FindItemDefinition(itemName);
if (asBP && itemDef.Blueprint != null && itemDef.Blueprint.isResearchable)
{
var blueprintBaseDef = ItemManager.FindItemDefinition("blueprintbase");
item = ItemManager.Create(blueprintBaseDef, 1, 0uL);
item.blueprintTarget = itemDef.itemid;
}
else
item = ItemManager.CreateByName(itemName, 1);
if (item == null || item.info == null)
continue;
break;
} while (true);
if (item == null)
return null;
object itemOptions;
if (((lootTables[type] as Dictionary<string, object>)["ItemList"] as Dictionary<string, object>).TryGetValue(item.info.shortname, out itemOptions))
{
Dictionary<string, object> options = itemOptions as Dictionary<string, object>;
item.amount = UnityEngine.Random.Range(Math.Min((int)options["Min"], (int)options["Max"]), Math.Max((int)options["Min"], (int)options["Max"])) * lootMultiplier;
//if (options.ContainsKey("SkinId"))
//item.skin = (uint)options["SkinId"];
}
item.OnVirginSpawn();
return item;
}
object OnLootSpawn(LootContainer container)
{
if (!initialized || container == null)
return null;
if (CustomLootSpawns != null && (CustomLootSpawns && (bool)CustomLootSpawns?.Call("IsLootBox", container.GetComponent<BaseEntity>())))
return null;
if (PopulateContainer(container))
{
ItemManager.DoRemoves();
return true;
}
return null;
}
static int RarityIndex(Rarity rarity)
{
switch (rarity)
{
case Rarity.None: return 0;
case Rarity.Common: return 1;
case Rarity.Uncommon: return 2;
case Rarity.Rare: return 3;
case Rarity.VeryRare: return 4;
}
return -1;
}
bool ItemExists(string name)
{
foreach (var def in ItemManager.itemList)
{
if (def.shortname != name)
continue;
var testItem = ItemManager.CreateByName(name, 1);
if (testItem != null)
{
testItem.Remove(0f);
return true;
}
}
return false;
}
bool isSupplyDropActive()
{
Dictionary<string, object> con;
object containerobj;
if (!lootTables.TryGetValue("assets/prefabs/misc/supply drop/supply_drop.prefab", out containerobj))
return false;
con = containerobj as Dictionary<string, object>;
if ((bool)con["Enabled"])
return true;
return false;
}
class StoredExportNames
{
public int version;
public Dictionary<string, string> AllItemsAvailable = new Dictionary<string, string>();
public StoredExportNames()
{
}
}
void SaveExportNames()
{
storedExportNames = Interface.GetMod().DataFileSystem.ReadObject<StoredExportNames>("BetterLoot\\NamesList");
if (storedExportNames.AllItemsAvailable.Count == 0 || (int)storedExportNames.version != Rust.Protocol.network)
{
storedExportNames = new StoredExportNames();
var exportItems = new List<ItemDefinition>(ItemManager.itemList);
storedExportNames.version = Rust.Protocol.network;
foreach (var it in exportItems)
storedExportNames.AllItemsAvailable.Add(it.shortname, it.displayName.english);
Interface.GetMod().DataFileSystem.WriteObject("BetterLoot\\NamesList", storedExportNames);
Puts($"Exported {storedExportNames.AllItemsAvailable.Count} items to 'NamesList'");
}
}
[ChatCommand("blacklist")]
void cmdChatBlacklist(BasePlayer player, string command, string[] args)
{
string usage = "Usage: /blacklist [additem|deleteitem] \"ITEMNAME\"";
if (!initialized)
{
SendReply(player, string.Format("Plugin not enabled."));
return;
}
if (args.Length == 0)
{
if (storedBlacklist.ItemList.Count == 0)
{
SendReply(player, string.Format("There are no blacklisted items"));
}
else
{
var sb = new StringBuilder();
foreach (var item in storedBlacklist.ItemList)
{
if (sb.Length > 0)
sb.Append(", ");
sb.Append(item);
}
SendReply(player, string.Format("Blacklisted items: {0}", sb.ToString()));
}
return;
}
if (!ServerUsers.Is(player.userID, ServerUsers.UserGroup.Owner))
{
//SendReply(player, string.Format(lang.GetMessage("msgNotAuthorized", this, player.UserIDString)));
SendReply(player, "You are not authorized to use this command");
return;
}
if (args.Length != 2)
{
SendReply(player, usage);
return;
}
if (args[0] == "additem")
{
if (!ItemExists(args[1]))
{
SendReply(player, string.Format("Not a valid item: {0}", args[1]));
return;
}
if (!storedBlacklist.ItemList.Contains(args[1]))
{
storedBlacklist.ItemList.Add(args[1]);
UpdateInternals(false);
SendReply(player, string.Format("The item '{0}' is now blacklisted", args[1]));
SaveBlacklist();
return;
}
else
{
SendReply(player, string.Format("The item '{0}' is already blacklisted", args[1]));
return;
}
}
else if (args[0] == "deleteitem")
{
if (!ItemExists(args[1]))
{
SendReply(player, string.Format("Not a valid item: {0}", args[1]));
return;
}
if (storedBlacklist.ItemList.Contains(args[1]))
{
storedBlacklist.ItemList.Remove(args[1]);
UpdateInternals(false);
SendReply(player, string.Format("The item '{0}' is now no longer blacklisted", args[1]));
SaveBlacklist();
return;
}
else
{
SendReply(player, string.Format("The item '{0}' is not blacklisted", args[1]));
return;
}
}
else
{
SendReply(player, usage);
return;
}
}
#region Hammer loot cycle
object OnMeleeAttack(BasePlayer player, HitInfo c)
{
//Puts($"OnMeleeAttack works! You hit {c.HitEntity.PrefabName}"); DEBUG FOR TESTING
var item = player.GetActiveItem();
if (item.hasCondition) return null;
//Puts($"{item.ToString()}");
if (!player.IsAdmin || c.HitEntity.GetComponent<LootContainer>() == null || !item.ToString().Contains("hammer") || !enableHammerLootCycle) return null;
var inv = c.HitEntity.GetComponent<StorageContainer>();
inv.gameObject.AddComponent<HammerHitLootCycle>();
player.inventory.loot.StartLootingEntity(inv, false);
player.inventory.loot.AddContainer(inv.inventory);
player.inventory.loot.SendImmediate();
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", inv.panelName);
//Timer s = timer.Every(1f, () => { PopulateContainer(inv})
return null;
}
class HammerHitLootCycle : FacepunchBehaviour
{
void Awake()
{
if (!bl.initialized) return;
InvokeRepeating(Repeater, (float)bl.hammerLootCycleTime, (float)bl.hammerLootCycleTime);
}
void Repeater()
{
if (!enabled) return;
LootContainer loot = GetComponent<LootContainer>();
bl.Puts($"{loot}");
bl.PopulateContainer(loot);
}
private void PlayerStoppedLooting(BasePlayer player)
{
//bl.Puts($"Ended looting of the box"); Doesn't call but it works for a reason I don't quite understand
CancelInvoke(Repeater);
Destroy(this);
}
}
#endregion
}
}

705
plugins/BlueprintShare.cs Normal file
View File

@ -0,0 +1,705 @@
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Blueprint Share", "c_creep", "1.2.4")]
[Description("Allows players to share researched blueprints with their friends, clan or team")]
class BlueprintShare : RustPlugin
{
#region Fields
[PluginReference] private Plugin Clans, ClansReborn, Friends;
private StoredData storedData;
private bool clansEnabled = true, friendsEnabled = true, teamsEnabled = true, recycleEnabled = false;
#endregion
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Prefix"] = "<color=#D85540>[Blueprint Share] </color>",
["ArgumentsError"] = "Error, incorrect arguments. Try /bs help.",
["Help"] = "<color=#D85540>Blueprint Share Help:</color>\n\n<color=#D85540>/bs toggle</color> - Toggles the sharing of blueprints.\n<color=#D85540>/bs share <player></color> - Shares your blueprints with other player.",
["ToggleOn"] = "You have enabled sharing blueprints.",
["ToggleOff"] = "You have disabled sharing blueprints.",
["NoPermission"] = "You don't have permission to use this command!",
["CannotShare"] = "You cannot share blueprints with this player because they aren't a friend or in the same clan or team!",
["NoTarget"] = "You didn't specifiy a player to share with!",
["TargetEqualsPlayer"] = "You cannot share blueprints with your self!",
["PlayerNotFound"] = "Couldn't find a player with that name!",
["MultiplePlayersFound"] = "Found multiple players with a similar name: {0}",
["ShareSuccess"] = "You shared {0} blueprints with {1}.",
["ShareFailure"] = "You don't have any new blueprints to share with {0}",
["ShareReceieve"] = "{0} has shared {1} blueprints with you.",
["Recycle"] = "You have kept the blueprint because no one learnt the blueprint.",
["ShareError"] = "An error occured while attempting to share items with another player"
}, this);
}
private string GetLangValue(string key, string id = null, params object[] args)
{
var msg = lang.GetMessage(key, this, id);
return args.Length > 0 ? string.Format(msg, args) : msg;
}
#endregion
#region Oxide Hooks
private void Init()
{
LoadData();
LoadDefaultConfig();
permission.RegisterPermission("blueprintshare.toggle", this);
permission.RegisterPermission("blueprintshare.share", this);
}
private void OnPlayerConnected(BasePlayer player)
{
var playerUID = player.UserIDString;
if (!PlayerDataExists(playerUID))
{
CreateNewPlayerData(playerUID);
}
}
private void OnItemAction(Item item, string action, BasePlayer player)
{
if (player != null)
{
if (action == "study")
{
var itemShortName = item.blueprintTargetDef.shortname;
if (CanShareBlueprint(itemShortName, player))
{
item.Remove();
}
}
}
}
private void OnTechTreeNodeUnlocked(Workbench workbench, TechTreeData.NodeInstance node, BasePlayer player)
{
if (workbench != null)
{
if (node != null)
{
if (player != null)
{
var itemShortName = node.itemDef.shortname;
CanShareBlueprint(itemShortName, player);
}
}
}
}
#endregion
#region General Methods
private bool CanShareBlueprint(string itemShortName, BasePlayer player)
{
if (player == null) return false;
if (string.IsNullOrEmpty(itemShortName)) return false;
var playerUID = player.UserIDString;
if (SharingEnabled(playerUID))
{
if (InTeam(player.userID) || InClan(player.userID) || HasFriends(player.userID))
{
if (SomeoneWillLearnBlueprint(player, itemShortName))
{
TryInsertBlueprint(player, itemShortName);
ShareWithPlayers(player, itemShortName);
HandleAdditionalBlueprints(player, itemShortName);
return true;
}
else
{
if (recycleEnabled)
{
player.ChatMessage(GetLangValue("Recycle", playerUID));
return true;
}
return false;
}
}
else
{
return false;
}
}
else
{
TryInsertBlueprint(player, itemShortName);
return true;
}
}
private void HandleAdditionalBlueprints(BasePlayer player, string itemShortName)
{
var additionalBlueprints = GetItemDefinition(itemShortName).Blueprint.additionalUnlocks;
if (additionalBlueprints.Count > 0)
{
foreach (var blueprint in additionalBlueprints)
{
var additionalItemShortName = blueprint.shortname;
if (!string.IsNullOrEmpty(additionalItemShortName))
{
if (SomeoneWillLearnBlueprint(player, additionalItemShortName))
{
ShareWithPlayers(player, additionalItemShortName);
}
}
}
}
}
private void ShareWithPlayers(BasePlayer sharer, string itemShortName)
{
if (sharer == null || string.IsNullOrEmpty(itemShortName)) return;
var recipients = SelectSharePlayers(sharer);
foreach (var recipient in recipients)
{
if (recipient != null)
{
if (UnlockBlueprint(recipient, itemShortName))
{
TryInsertBlueprint(recipient, itemShortName);
}
}
}
}
private void ShareWithPlayer(BasePlayer sharer, BasePlayer recipient)
{
var sharerUID = sharer.UserIDString;
var recipientUID = recipient.UserIDString;
if (SameTeam(sharer, recipient) || SameClan(sharerUID, recipientUID) || AreFriends(sharerUID, recipientUID))
{
var itemShortNames = LoadBlueprints(sharerUID);
if (itemShortNames != null)
{
if (itemShortNames.Count > 0)
{
var learnedBlueprints = 0;
foreach (var itemShortName in itemShortNames)
{
if (recipient == null || string.IsNullOrEmpty(itemShortName)) return;
if (UnlockBlueprint(recipient, itemShortName))
{
TryInsertBlueprint(recipient, itemShortName);
learnedBlueprints++;
}
}
if (learnedBlueprints > 0)
{
sharer.ChatMessage(GetLangValue("Prefix", sharerUID) + GetLangValue("ShareSuccess", sharerUID, learnedBlueprints, recipient.displayName));
recipient.ChatMessage(GetLangValue("Prefix", recipientUID) + GetLangValue("ShareReceieve", recipientUID, sharer.displayName, learnedBlueprints));
}
else
{
sharer.ChatMessage(GetLangValue("Prefix", sharerUID) + GetLangValue("ShareFailure", sharerUID, recipient.displayName));
}
}
else
{
sharer.ChatMessage(GetLangValue("Prefix", sharerUID) + GetLangValue("ShareFailure", sharerUID, recipient.displayName));
}
}
else
{
sharer.ChatMessage(GetLangValue("ShareError", sharerUID));
}
}
}
private bool UnlockBlueprint(BasePlayer player, string itemShortName)
{
if (player == null) return false;
if (string.IsNullOrEmpty(itemShortName)) return false;
var blueprintComponent = player.blueprints;
if (blueprintComponent == null) return false;
var itemDefinition = GetItemDefinition(itemShortName);
if (itemDefinition == null) return false;
if (blueprintComponent.HasUnlocked(itemDefinition)) return false;
var soundEffect = new Effect("assets/prefabs/deployable/research table/effects/research-success.prefab", player.transform.position, Vector3.zero);
if (soundEffect == null) return false;
EffectNetwork.Send(soundEffect, player.net.connection);
blueprintComponent.Unlock(itemDefinition);
return true;
}
private bool SomeoneWillLearnBlueprint(BasePlayer sharer, string itemShortName)
{
if (sharer == null || string.IsNullOrEmpty(itemShortName)) return false;
var players = SelectSharePlayers(sharer);
if (players.Count > 0)
{
var blueprintItem = GetItemDefinition(itemShortName);
if (blueprintItem != null)
{
var counter = 0;
foreach (var player in players)
{
if (player != null)
{
if (!player.blueprints.HasUnlocked(blueprintItem))
{
counter++;
}
}
}
return counter > 0;
}
else
{
return false;
}
}
else
{
return false;
}
}
private List<BasePlayer> SelectSharePlayers(BasePlayer player)
{
var playersToShareWith = new List<BasePlayer>();
var playerUID = player.userID;
if (clansEnabled && (Clans != null || ClansReborn != null) && InClan(playerUID))
{
playersToShareWith.AddRange(GetClanMembers(playerUID));
}
if (friendsEnabled && Friends != null && HasFriends(playerUID))
{
playersToShareWith.AddRange(GetFriends(playerUID));
}
if (teamsEnabled && InTeam(playerUID))
{
playersToShareWith.AddRange(GetTeamMembers(playerUID));
}
return playersToShareWith;
}
private List<string> LoadBlueprints(string playerUID)
{
if (PlayerDataExists(playerUID))
{
return storedData.players[playerUID].learntBlueprints;
}
else
{
CreateNewPlayerData(playerUID);
if (storedData.players[playerUID].learntBlueprints == null)
{
return storedData.players[playerUID].learntBlueprints = new List<string>();
}
else
{
return storedData.players[playerUID].learntBlueprints;
}
}
}
private void TryInsertBlueprint(BasePlayer player, string itemShortName)
{
var playerUID = player.UserIDString;
if (PlayerDataExists(playerUID))
{
InsertBlueprint(playerUID, itemShortName);
}
else
{
CreateNewPlayerData(playerUID);
InsertBlueprint(playerUID, itemShortName);
}
}
private void InsertBlueprint(string playerUID, string itemShortName)
{
if (string.IsNullOrEmpty(playerUID) || string.IsNullOrEmpty(itemShortName)) return;
if (!storedData.players[playerUID].learntBlueprints.Contains(itemShortName))
{
storedData.players[playerUID].learntBlueprints.Add(itemShortName);
SaveData();
}
}
#endregion
#region Config
protected override void LoadDefaultConfig()
{
Config["ClansEnabled"] = clansEnabled = GetConfigValue("ClansEnabled", true);
Config["FriendsEnabled"] = friendsEnabled = GetConfigValue("FriendsEnabled", true);
Config["TeamsEnabled"] = teamsEnabled = GetConfigValue("TeamsEnabled", true);
Config["RecycleBlueprints"] = recycleEnabled = GetConfigValue("RecycleBlueprints", false);
SaveConfig();
}
private T GetConfigValue<T>(string name, T defaultValue)
{
return Config[name] == null ? defaultValue : (T)Convert.ChangeType(Config[name], typeof(T));
}
#endregion
#region Friends Methods
private bool HasFriends(ulong playerUID)
{
if (Friends == null) return false;
var friendsList = Friends.Call<ulong[]>("GetFriends", playerUID);
return friendsList != null && friendsList.Length != 0;
}
private List<BasePlayer> GetFriends(ulong playerUID)
{
var friendsList = new List<BasePlayer>();
var friends = Friends.Call<ulong[]>("GetFriends", playerUID);
foreach (var friendUID in friends)
{
var friend = RustCore.FindPlayerById(friendUID);
friendsList.Add(friend);
}
return friendsList;
}
private bool AreFriends(string sharerUID, string playerUID) => Friends == null ? false : Friends.Call<bool>("AreFriends", sharerUID, playerUID);
#endregion
#region Clan Methods
private bool InClan(ulong playerUID)
{
if (ClansReborn == null && Clans == null) return false;
var clanName = Clans?.Call<string>("GetClanOf", playerUID);
return clanName != null;
}
private List<BasePlayer> GetClanMembers(ulong playerUID)
{
var membersList = new List<BasePlayer>();
var clanName = Clans?.Call<string>("GetClanOf", playerUID);
if (!string.IsNullOrEmpty(clanName))
{
var clan = Clans?.Call<JObject>("GetClan", clanName);
if (clan != null && clan is JObject)
{
var members = clan.GetValue("members");
if (members != null)
{
foreach (var member in members)
{
ulong clanMemberUID;
if (!ulong.TryParse(member.ToString(), out clanMemberUID)) continue;
BasePlayer clanMember = RustCore.FindPlayerById(clanMemberUID);
membersList.Add(clanMember);
}
}
}
}
return membersList;
}
private bool SameClan(string sharerUID, string playerUID) => ClansReborn == null && Clans == null ? false : (bool)Clans?.Call<bool>("IsClanMember", sharerUID, playerUID);
#endregion
#region Team Methods
private bool InTeam(ulong playerUID)
{
var player = RustCore.FindPlayerById(playerUID);
return player.currentTeam != 0;
}
private List<BasePlayer> GetTeamMembers(ulong playerUID)
{
var membersList = new List<BasePlayer>();
var player = RustCore.FindPlayerById(playerUID);
var teamMembers = player.Team.members;
foreach (var teamMemberUID in teamMembers)
{
var teamMember = RustCore.FindPlayerById(teamMemberUID);
if (teamMember != null)
{
membersList.Add(teamMember);
}
}
return membersList;
}
private bool SameTeam(BasePlayer sharer, BasePlayer player) => sharer.currentTeam == player.currentTeam;
#endregion
#region Utility Methods
private BasePlayer FindPlayer(string playerName, BasePlayer player, string playerUID)
{
var targets = FindPlayers(playerName);
if (targets.Count <= 0)
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("PlayerNotFound", playerUID));
return null;
}
if (targets.Count > 1)
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("MultiplePlayersFound", playerUID));
return null;
}
return targets.First();
}
private List<BasePlayer> FindPlayers(string playerName)
{
if (string.IsNullOrEmpty(playerName)) return null;
return BasePlayer.allPlayerList.Where(p => p && p.UserIDString == playerName || p.displayName.Contains(playerName, CompareOptions.OrdinalIgnoreCase)).ToList();
}
private ItemDefinition GetItemDefinition(string itemShortName)
{
if (string.IsNullOrEmpty(itemShortName)) return null;
var itemDefinition = ItemManager.FindItemDefinition(itemShortName.ToLower());
return itemDefinition;
}
#endregion
#region Data
private class StoredData
{
public Dictionary<string, PlayerData> players = new Dictionary<string, PlayerData>();
}
private class PlayerData
{
public bool sharingEnabled;
public List<string> learntBlueprints;
}
private void CreateData()
{
storedData = new StoredData();
SaveData();
}
private void LoadData()
{
if (Interface.Oxide.DataFileSystem.ExistsDatafile(Name))
{
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
}
else
{
CreateData();
}
}
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
private bool PlayerDataExists(string playerUID) => storedData.players.ContainsKey(playerUID);
private void CreateNewPlayerData(string playerUID)
{
storedData.players.Add(playerUID, new PlayerData
{
sharingEnabled = true,
learntBlueprints = new List<string>()
});
SaveData();
}
#endregion
#region Chat Commands
[ChatCommand("bs")]
private void ToggleCommand(BasePlayer player, string command, string[] args)
{
var playerUID = player.UserIDString;
if (args.Length < 1)
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("Help", playerUID));
return;
}
switch (args[0].ToLower())
{
case "help":
{
player.ChatMessage(GetLangValue("Help", playerUID));
break;
}
case "toggle":
{
if (permission.UserHasPermission(playerUID, "blueprintshare.toggle"))
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue(SharingEnabled(playerUID) ? "ToggleOff" : "ToggleOn", playerUID));
if (storedData.players.ContainsKey(playerUID))
{
storedData.players[playerUID].sharingEnabled = !storedData.players[playerUID].sharingEnabled;
SaveData();
}
}
else
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("NoPermission", playerUID));
}
break;
}
case "share":
{
if (permission.UserHasPermission(playerUID, "blueprintshare.share"))
{
if (args.Length == 2)
{
var target = FindPlayer(args[1], player, playerUID);
if (target == null) return;
if (target == player)
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("TargetEqualsPlayer", playerUID));
return;
}
ShareWithPlayer(player, target);
}
else
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("NoTarget", playerUID));
return;
}
}
else
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("NoPermission", playerUID));
}
break;
}
default:
{
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("ArgumentsError", playerUID));
break;
}
}
}
#endregion
#region API
private bool SharingEnabled(string playerUID) => storedData.players.ContainsKey(playerUID) ? storedData.players[playerUID].sharingEnabled : true;
#endregion
}
}

1318
plugins/Clans.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,693 @@
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using System.Collections.Generic;
using System.Linq;
namespace Oxide.Plugins
{
[Info("Crafting Controller", "Whispers88", "3.2.2")]
[Description("Allows you to modify the time spend crafting and which items can be crafted")]
//Credits to previous authors Nivex & Mughisi
public class CraftingController : RustPlugin
{
#region Config
private Configuration config;
private static Dictionary<string, float> defaultsetup = new Dictionary<string, float>();
public class CraftingData
{
public bool canCraft;
public bool canResearch;
public bool useCrafteRateMultiplier;
public float craftTime;
public int workbenchLevel;
public ulong defaultskinid;
public CraftingData()
{
canCraft = true;
canResearch = true;
useCrafteRateMultiplier = true;
craftTime = 0;
workbenchLevel = -1;
defaultskinid = 0;
}
}
public class Configuration
{
[JsonProperty("Default crafting rate percentage")]
public float CraftingRate = 50;
[JsonProperty("Save commands to config (save config changes via command to the configuration)")]
public bool SaveCommands = true;
[JsonProperty("Simple Mode (disables: instant bulk craft, skin options and full inventory checks for better performance)")]
public bool SimpleMode = false;
[JsonProperty("Allow crafting when inventory is full")]
public bool FullInventory = false;
[JsonProperty("Complete crafting on server shut down")]
public bool CompleteCrafting = false;
[JsonProperty("Craft items with random skins if not already skinned")]
public bool RandomSkins = false;
[JsonProperty("Show Crafting Notes")]
public bool ShowCraftNotes = false;
[JsonProperty("Crafting rate bonus mulitplier (apply oxide perms for additional mulitpliers")]
public Dictionary<string, float> BonusMultiplier = new Dictionary<string, float>() { { "vip1", 90 }, { "vip2", 80 } };
[JsonProperty("Advanced Crafting Options")]
public Dictionary<string, CraftingData> CraftingOptions = new Dictionary<string, CraftingData>();
public string ToJson() => JsonConvert.SerializeObject(this);
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null)
{
throw new JsonException();
}
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
{
PrintToConsole("Configuration appears to be outdated; updating and saving");
SaveConfig();
}
}
catch
{
PrintToConsole($"Configuration file {Name}.json is invalid; using defaults");
LoadDefaultConfig();
}
}
protected override void SaveConfig()
{
PrintToConsole($"Configuration changes saved to {Name}.json");
Config.WriteObject(config, true);
}
#endregion Config
#region Init
private const string perminstantbulkcraft = "craftingcontroller.instantbulkcraft";
private const string permblockitems = "craftingcontroller.blockitems";
private const string permitemrate = "craftingcontroller.itemrate";
private const string permcraftingrate = "craftingcontroller.craftingrate";
private const string permsetbenchlvl = "craftingcontroller.setbenchlvl";
private const string permsetskins = "craftingcontroller.setskins";
private List<string> permissions = new List<string> { perminstantbulkcraft, permblockitems, permitemrate, permcraftingrate, permsetbenchlvl, permsetskins };
private List<string> permissionsBonusMultiplier = new List<string>();
private List<string> commands = new List<string> { nameof(CommandCraftingRate), nameof(CommandCraftTime), nameof(CommandBlockItem), nameof(CommandUnblockItem), nameof(CommandSetDefaultSkin), nameof(CommandWorkbenchLVL) };
private void OnServerInitialized()
{
ItemManager.bpList.ForEach(bp => defaultsetup[bp.name] = bp.time);
config.BonusMultiplier.Keys.ToList().ForEach(perm => permissionsBonusMultiplier.Add("craftingcontroller." + perm));
//register permissions
permissions.ForEach(perm => permission.RegisterPermission(perm, this));
permissionsBonusMultiplier.ForEach(perm => permission.RegisterPermission(perm, this));
//register commands
commands.ForEach(command => AddLocalizedCommand(command));
if (config.SimpleMode)
{
Unsubscribe("OnItemCraft");
Unsubscribe("OnItemCraftFinished");
Unsubscribe("OnItemCraftCancelled");
}
var bplist = ItemManager.bpList.Where(item => config.CraftingOptions.ContainsKey(item.targetItem.shortname) == false).ToList();
bplist.ForEach(x => config.CraftingOptions.Add(x.targetItem.shortname, new CraftingData() { craftTime = x.time, workbenchLevel = x.workbenchLevelRequired }));
SaveConfig();
UpdateCraftingRate();
}
private void Unload()
{
ItemManager.bpList.ForEach(bp => bp.time = defaultsetup[bp.name]);
}
#endregion Init
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoInvSpace"] = "You don't have enough room to craft this item!",
["NoPerms"] = "You don't have permission to use this command.",
["CannotFindItem"] = "Cannot find item {0}.",
["ItemBlocked"] = "{0} has been blocked from crafting.",
["ItemUnblocked"] = "{0} has been unblocked from crafting.",
["NeedsAdvancedOptions"] = "You need to enable advanced crafting options in your config to use this.",
["WrongNumberInput"] = "Your input needs to be a number.",
["ItemCraftTimeSet"] = "{0} craft time set to {1} seconds",
["WorkbenchLevelSet"] = "{0} workbench level set to {1}",
["CurrentCraftinRate"] = "The current crafting rate is {0 }%",
["CraftingRateUpdated"] = "The crafting rate was updated to {0} %",
["CraftTime2Args"] = "This command needs two arguments in the format /crafttime item.shortname timetocraft",
["BlockItem1Args"] = "This command needs one argument in the format /blockitem item.shortname",
["UnblockItem1Args"] = "This command needs one argument in the format /unblockitem item.shortname",
["WorckBenchLvl2Args"] = "This command needs two arguments in the format /benchlvl item.shortname workbenchlvl",
["BenchLevelInput"] = "The work bench level must be between 0 and 3",
["SetSkin2Args"] = "This command needs one argument in the format /setcraftskin item.shortname skinworkshopid",
["SkinSet"] = "The default skin for {0} was set to {1}",
["CraftTimeCheck"] = "The craft time of this item is {0}",
//Commands
["CommandCraftingRate"] = "craftrate",
["CommandCraftTime"] = "crafttime",
["CommandBlockItem"] = "blockitem",
["CommandUnblockItem"] = "unblockitem",
["CommandWorkbenchLVL"] = "benchlvl",
["CommandSetDefaultSkin"] = "setcraftskin"
}, this);
}
#endregion Localization
#region Commands
private void CommandCraftingRate(IPlayer iplayer, string command, string[] args)
{
if (!HasPerm(iplayer.Id, permitemrate))
{
Message(iplayer, "NoPerms");
return;
}
int craftingrate;
if (args.Length == 0)
{
Message(iplayer, "CurrentCraftinRate", config.CraftingRate);
return;
}
if (!int.TryParse(args[0], out craftingrate))
{
Message(iplayer, "WrongNumberInput");
return;
}
if (craftingrate < 0) craftingrate = 0;
config.CraftingRate = craftingrate;
UpdateCraftingRate();
Message(iplayer, "CraftingRateUpdated", config.CraftingRate);
if (config.SaveCommands) SaveConfig();
}
private void CommandCraftTime(IPlayer iplayer, string command, string[] args)
{
if (!HasPerm(iplayer.Id, permitemrate))
{
Message(iplayer, "NoPerms");
return;
}
if (args.Count() == 1)
{
var itemcheck = FindItem(args[0]);
if (itemcheck)
{
Message(iplayer, "CraftTimeCheck", itemcheck.Blueprint.time);
return;
}
}
if (args.Count() < 2)
{
Message(iplayer, "CraftTime2Args");
return;
}
var setitem = FindItem(args[0]);
if (!setitem)
{
Message(iplayer, "CannotFindItem", args[0]);
return;
}
if (args[1].ToLower() == "default")
{
config.CraftingOptions[setitem.shortname].useCrafteRateMultiplier = true;
config.CraftingOptions[setitem.shortname].craftTime = (defaultsetup[setitem.Blueprint.name] * (config.CraftingRate / 100));
Message(iplayer, "ItemCraftTimeSet", setitem.shortname, (setitem.Blueprint.time).ToString());
if (config.SaveCommands) SaveConfig();
return;
}
int crafttime;
if (!int.TryParse(args[1], out crafttime))
{
Message(iplayer, "WrongNumberInput");
return;
}
config.CraftingOptions[setitem.shortname].craftTime = crafttime;
config.CraftingOptions[setitem.shortname].useCrafteRateMultiplier = false;
var bp = ItemManager.bpList.Where(item => item.targetItem.shortname == setitem.shortname).FirstOrDefault();
bp.time = crafttime;
Message(iplayer, "ItemCraftTimeSet", setitem.shortname, crafttime.ToString());
if (config.SaveCommands) SaveConfig();
}
private void CommandBlockItem(IPlayer iplayer, string command, string[] args)
{
if (!HasPerm(iplayer.Id, permblockitems))
{
Message(iplayer, "NoPerms");
return;
}
if (args.Count() < 1)
{
Message(iplayer, "BlockItem1Args");
return;
}
var blockitem = FindItem(args[0]);
if (!blockitem)
{
Message(iplayer, "CannotFindItem", args[0]);
return;
}
config.CraftingOptions[blockitem.shortname].canCraft = false;
config.CraftingOptions[blockitem.shortname].canResearch = false;
var bp = ItemManager.bpList.Where(item => item.targetItem.shortname == blockitem.shortname).FirstOrDefault();
bp.userCraftable = false;
bp.isResearchable = false;
Message(iplayer, "ItemBlocked", blockitem.shortname);
if (config.SaveCommands) SaveConfig();
}
private void CommandUnblockItem(IPlayer iplayer, string command, string[] args)
{
if (!HasPerm(iplayer.Id, permblockitems))
{
Message(iplayer, "NoPerms");
return;
}
if (args.Count() < 1)
{
Message(iplayer, "UnbockItem1Args");
return;
}
var blockitem = FindItem(args[0]);
if (!blockitem)
{
Message(iplayer, "CannotFindItem", args[0]);
return;
}
config.CraftingOptions[blockitem.shortname].canCraft = true;
config.CraftingOptions[blockitem.shortname].canResearch = true;
var bp = ItemManager.bpList.Where(item => item.targetItem.shortname == blockitem.shortname).FirstOrDefault();
bp.userCraftable = true;
bp.isResearchable = true;
Message(iplayer, "ItemUnblocked", blockitem.shortname);
if (config.SaveCommands) SaveConfig();
}
private void CommandWorkbenchLVL(IPlayer iplayer, string command, string[] args)
{
if (!HasPerm(iplayer.Id, permsetbenchlvl))
{
Message(iplayer, "NoPerms");
return;
}
if (args.Count() < 2)
{
Message(iplayer, "WorckBenchLvl2Args");
return;
}
var item = FindItem(args[0]);
if (!item)
{
Message(iplayer, "CannotFindItem", args[0]);
return;
}
int benchlvl;
if (!int.TryParse(args[1], out benchlvl))
{
Message(iplayer, "WrongNumberInput");
return;
}
if (benchlvl < 0 || benchlvl > 3)
{
Message(iplayer, "BenchLevelInput");
return;
}
config.CraftingOptions[item.shortname].workbenchLevel = benchlvl;
var bp = ItemManager.bpList.Where(x => x.targetItem.shortname == item.shortname).FirstOrDefault();
bp.workbenchLevelRequired = benchlvl;
Message(iplayer, "WorkbenchLevelSet", item.shortname, benchlvl.ToString());
if (config.SaveCommands) SaveConfig();
}
private void CommandSetDefaultSkin(IPlayer iplayer, string command, string[] args)
{
if (!HasPerm(iplayer.Id, permsetskins))
{
Message(iplayer, "NoPerms");
return;
}
if (args.Count() < 2)
{
Message(iplayer, "SetSkin2Args");
return;
}
var setitem = FindItem(args[0]);
if (!setitem)
{
Message(iplayer, "CannotFindItem", args[0]);
return;
}
ulong skinid;
if (!ulong.TryParse(args[1], out skinid))
{
Message(iplayer, "WrongNumberInput", args);
return;
}
config.CraftingOptions[setitem.shortname].defaultskinid = skinid;
Message(iplayer, "SkinSet", setitem.shortname, skinid.ToString());
if (config.SaveCommands) SaveConfig();
}
#endregion Commands
#region Methods
private void UpdateCraftingRate()
{
foreach (var bp in ItemManager.bpList)
{
CraftingData data;
if (!config.CraftingOptions.TryGetValue(bp.targetItem.shortname, out data)) continue;
if (!data.canCraft)
{
bp.userCraftable = false;
continue;
}
if (!data.canResearch)
{
bp.isResearchable = false;
continue;
}
if (!data.useCrafteRateMultiplier)
{
bp.time = data.craftTime;
continue;
}
if (config.CraftingRate == 0f)
{
bp.time = 0f;
continue;
}
bp.time *= (float)(config.CraftingRate / 100);
if (data.workbenchLevel > -1 && data.workbenchLevel < 4)
bp.workbenchLevelRequired = data.workbenchLevel;
}
}
private void InstantBulkCraft(BasePlayer player, ItemCraftTask task, ItemDefinition item, List<int> stacks, int craftSkin, ulong skin)
{
if (skin == 0uL)
{
skin = ItemDefinition.FindSkin(item.itemid, craftSkin);
}
foreach (var stack in stacks)
{
var itemtogive = ItemManager.Create(item, stack, craftSkin != 0 && skin == 0uL ? (ulong)craftSkin : skin);
var held = itemtogive.GetHeldEntity();
if (held != null)
{
held.skinID = skin == 0uL ? (ulong)craftSkin : skin;
held.SendNetworkUpdate();
}
player.GiveItem(itemtogive);
if (config.ShowCraftNotes) player.Command(string.Concat(new object[] { "note.inv ", item.itemid, " ", stack }), new object[0]);
Interface.CallHook("OnItemCraftFinished", task, itemtogive);
}
}
private static void CompleteCrafting(BasePlayer player)
{
if (player.inventory.crafting.queue.Count == 0) return;
player.inventory.crafting.FinishCrafting(player.inventory.crafting.queue.First.Value);
player.inventory.crafting.queue.RemoveFirst();
}
private static void CancelAllCrafting(BasePlayer player)
{
var crafter = player.inventory.crafting;
crafter.queue.ToList().ForEach(x => crafter.CancelTask(x.taskUID, true));
}
#endregion Methods
#region Hooks
private Dictionary<ItemCraftTask, ulong> skinupdate = new Dictionary<ItemCraftTask, ulong>();
private object OnItemCraft(ItemCraftTask task, BasePlayer crafter)
{
var player = task.owner;
var target = task.blueprint.targetItem;
if (task.instanceData?.dataInt != null) return null;
var stacks = GetStacks(target, task.amount * task.blueprint.amountToCreate);
ulong defaultskin = 0uL;
int freeslots = FreeSlots(player);
if (!config.FullInventory && stacks.Count >= freeslots)
{
int space = FreeSpace(player, target);
if (space < 1)
{
ReturnCraft(task, player);
return false;
}
int taskamt = task.amount * task.blueprint.amountToCreate;
for (int i = 0; i < 20 && taskamt > space; i++)
{
var oldtaskamt = taskamt;
taskamt = space;
foreach (var item in task.takenItems)
{
var itemtogive = item;
double fraction = (double)taskamt / (double)oldtaskamt;
int amttogive = (int)(item.amount * (1 - fraction));
if (amttogive <= 1)
{
ReturnCraft(task, player);
return false;
}
itemtogive = ItemManager.Create(item.info, amttogive, 0uL);
item.amount -= amttogive;
player.GiveItem(itemtogive);
}
space -= (freeslots - FreeSlots(player)) * target.stackable;
if (space < 1 || taskamt < 1)
{
ReturnCraft(task, player);
return false;
}
if (taskamt <= space) break;
}
task.amount = (int)(taskamt / task.blueprint.amountToCreate);
}
if (task.skinID == 0)
{
CraftingData data;
if (config.CraftingOptions.TryGetValue(target.shortname, out data))
{
defaultskin = data.defaultskinid;
}
if (config.RandomSkins && defaultskin == 0)
{
var skins = GetSkins(ItemManager.FindItemDefinition(target.itemid));
defaultskin = skins.GetRandom();
}
if (defaultskin > 999999)
skinupdate[task] = defaultskin;
else
task.skinID = (int)defaultskin;
}
List<string> bonusperms = permissionsBonusMultiplier.Where(perm => HasPerm(player.UserIDString, perm)).ToList();
if (bonusperms.Count > 0)
{
task.blueprint.time *= (float)(config.BonusMultiplier[bonusperms.First().Split('.')[1].ToString()] / 100);
}
if (task.blueprint.time == 0f || HasPerm(player.UserIDString, perminstantbulkcraft))
{
skinupdate.Remove(task);
stacks = GetStacks(target, task.amount * task.blueprint.amountToCreate);
InstantBulkCraft(player, task, target, stacks, task.skinID, defaultskin);
task.cancelled = true;
return false;
}
return null;
}
private void OnItemCraftFinished(ItemCraftTask task, Item item)
{
ulong skinid;
if (!skinupdate.TryGetValue(task, out skinid)) return;
item.skin = skinid;
var held = item.GetHeldEntity();
if (held != null)
{
held.skinID = skinid;
held.SendNetworkUpdate();
}
if (task.amount == 0)
skinupdate.Remove(task);
}
void OnItemCraftCancelled(ItemCraftTask task)
{
ulong skinid;
if (!skinupdate.TryGetValue(task, out skinid)) return;
skinupdate.Remove(task);
}
private void OnServerQuit()
{
foreach (var player in BasePlayer.activePlayerList.Where(player => player.inventory.crafting.queue.Count > 0))
{
if (config.CompleteCrafting)
CompleteCrafting(player);
CancelAllCrafting(player);
}
}
#endregion Hooks
#region Helpers
private void ReturnCraft(ItemCraftTask task, BasePlayer crafter)
{
task.cancelled = true;
Message(crafter.IPlayer, "NoInvSpace");
foreach (var item in task.takenItems.Where(x => x.amount > 0)) task.owner.GiveItem(item);
}
private ItemDefinition FindItem(string itemNameOrId)
{
ItemDefinition itemDef = ItemManager.FindItemDefinition(itemNameOrId.ToLower());
if (itemDef == null)
{
int itemId;
if (int.TryParse(itemNameOrId, out itemId))
{
itemDef = ItemManager.FindItemDefinition(itemId);
}
}
return itemDef;
}
private int FreeSpace(BasePlayer player, ItemDefinition item)
{
var slots = player.inventory.containerMain.capacity + player.inventory.containerBelt.capacity;
List<Item> containeritems = new List<Item>();
Dictionary<ItemDefinition, int> queueamts = new Dictionary<ItemDefinition, int>();
containeritems.AddRange(player.inventory.containerMain.itemList);
containeritems.AddRange(player.inventory.containerBelt.itemList);
int value = 0;
//Sum all items in crafting queue not including the item to be crafted
foreach (var queueitem in player.inventory.crafting.queue)
{
if (queueitem.blueprint.targetItem == item) continue;
if (queueamts.TryGetValue(queueitem.blueprint.targetItem, out value))
{
queueamts[queueitem.blueprint.targetItem] += queueitem.amount * queueitem.blueprint.amountToCreate;
continue;
}
queueamts[queueitem.blueprint.targetItem] = (queueitem.amount * queueitem.blueprint.amountToCreate);
}
//Take into account room of other stacks
int queuestacks = 0;
queueamts.ToList().ForEach(i => queuestacks += GetStacks(i.Key, i.Value - Stackroom(containeritems, i.Key.shortname)).Count);
//calculate total room in inventory for the item required
int invstackroom = (slots - containeritems.Count - queuestacks) * item.stackable;
invstackroom += containeritems.Where(x => x.info == item && x.amount < x.MaxStackable()).Sum(x => x.MaxStackable() - x.amount);
invstackroom -= player.inventory.crafting.queue.ToList().Where(x => x.blueprint.targetItem.shortname == item.shortname).Sum(x => x.amount * x.blueprint.amountToCreate);
return invstackroom;
}
private int FreeSlots(BasePlayer player)
{
var slots = player.inventory.containerMain.capacity + player.inventory.containerBelt.capacity;
var taken = player.inventory.containerMain.itemList.Count + player.inventory.containerBelt.itemList.Count;
return slots - taken;
}
private int Stackroom(List<Item> items, string item)
{
return items.Where(x => x.info.shortname == item && x.amount < x.MaxStackable()).Sum(x => x.MaxStackable() - x.amount);
}
private List<int> GetStacks(ItemDefinition item, int amount)
{
var list = new List<int>();
var maxStack = item.stackable;
while (amount > maxStack)
{
amount -= maxStack;
list.Add(maxStack);
}
list.Add(amount);
return list;
}
private readonly Dictionary<string, List<ulong>> skinsCache = new Dictionary<string, List<ulong>>();
private List<ulong> GetSkins(ItemDefinition def)
{
List<ulong> skins;
if (skinsCache.TryGetValue(def.shortname, out skins)) return skins;
skins = new List<ulong>();
skins.AddRange(ItemSkinDirectory.ForItem(def).Select(skin => (ulong)skin.id));
skins.AddRange(Rust.Workshop.Approved.All.Values.Where(skin => skin.Skinnable.ItemName == def.shortname).Select(skin => skin.WorkshopdId));
skinsCache.Add(def.shortname, skins);
return skins;
}
private string GetLang(string langKey, string playerId = null, params object[] args)
{
return string.Format(lang.GetMessage(langKey, this, playerId), args);
}
private void Message(IPlayer player, string langKey, params object[] args)
{
if (player.IsConnected) player.Message(GetLang(langKey, player.Id, args));
}
private bool HasPerm(string id, string perm) => permission.UserHasPermission(id, perm);
private void AddLocalizedCommand(string command)
{
foreach (string language in lang.GetLanguages(this))
{
Dictionary<string, string> messages = lang.GetMessages(language, this);
foreach (KeyValuePair<string, string> message in messages)
{
if (!message.Key.Equals(command)) continue;
if (string.IsNullOrEmpty(message.Value)) continue;
AddCovalenceCommand(message.Value, command);
}
}
}
#endregion Helpers
}
}

513
plugins/DiscordAuth.cs Normal file
View File

@ -0,0 +1,513 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Ext.Discord;
using Oxide.Ext.Discord.Attributes;
using Oxide.Ext.Discord.DiscordObjects;
namespace Oxide.Plugins
{
[Info("Discord Auth", "Tricky", "1.1.3")]
[Description("Allows players to connect their discord account with steam")]
public class DiscordAuth : CovalencePlugin
{
#region Defined
[DiscordClient]
private DiscordClient Client;
#endregion
#region Config
Configuration config;
class Configuration
{
[JsonProperty(PropertyName = "Settings")]
public Settings Info = new Settings();
[JsonProperty(PropertyName = "Authentication Code")]
public AuthCode Code = new AuthCode();
public class Settings
{
[JsonProperty(PropertyName = "Bot Token")]
public string BotToken = string.Empty;
[JsonProperty(PropertyName = "Oxide Group")]
public string Group = "authenticated";
[JsonProperty(PropertyName = "Enable Logging")]
public bool Log = false;
[JsonProperty(PropertyName = "Auth Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] AuthCommands = new string[] { "auth", "authenticate" };
[JsonProperty(PropertyName = "Deauth Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] DeauthCommands = new string[] { "deauth", "deauthenticate" };
[JsonProperty(PropertyName = "Discord Roles to Assign", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Roles = new List<string>()
{
"Authenticated"
};
[JsonProperty(PropertyName = "Revoke Oxide Group on Discord Leave")]
public bool RemovefromGroup = true;
[JsonProperty(PropertyName = "Deauthenticate on Discord Leave")]
public bool Deauthenticate = false;
[JsonProperty(PropertyName = "Chat Prefix")]
public string ChatPrefix = "[#1874CD](Auth)[/#]:";
}
public class AuthCode
{
[JsonProperty(PropertyName = "Code Lifetime (minutes)")]
public int CodeLifetime = 60;
[JsonProperty(PropertyName = "Code Length")]
public int CodeLength = 5;
[JsonProperty(PropertyName = "Lowercase")]
public bool Lowercase = false;
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null) throw new Exception();
}
catch
{
Config.WriteObject(config, false, $"{Interface.Oxide.ConfigDirectory}/{Name}.jsonError");
PrintError("The configuration file contains an error and has been replaced with a default config.\n" +
"The error configuration file was saved in the .jsonError extension");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Classes and Stored Data
private enum MemberRole { Add, Remove }
private const string authPerm = "discordauth.auth";
private const string deauthPerm = "discordauth.deauth";
private Data data;
private class Data
{
public Dictionary<string, string> Players = new Dictionary<string, string>();
}
private Dictionary<string, string> Codes = new Dictionary<string, string>();
#endregion
#region Lang
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Code Generation"] = "Here is your code: [#1874CD]{0}[/#]\nJoin our [#EE3B3B]Discord[/#] and PM the code to the Discord Bot",
["Code Expired"] = "Your code has [#EE3B3B]Expired![/#]",
["Authenticated"] = "Thank you for authenticating your account",
["Game-Deauthenticated"] = "Successfully deauthenticated your account",
["Discord-Deauthenticated"] = "You have been deauthenticated from {0}",
["Already Authenticated"] = "You have already [#1874CD]authenticated[/#] your account, no need to do it again",
["Not Authenticated"] = "You are not authenticated",
["Group Revoked"] = "Your '{0}' Group has been revoked! Join the server back to achieve it",
["Group Granted"] = "Granted '{0}' Group and the discord roles for joining {1} back",
["Unable to find code"] = "Sorry, we couldn't find your code, please try to authenticate again, If you haven't generated a code, please type /auth in-game",
["No Permission"] = "You dont have permission to use this command"
}, this);
}
#endregion
#region Commands
private void AuthCommand(IPlayer player, string command, string[] args)
{
// No Permission
if (!player.HasPermission(authPerm))
{
Message(player, "No Permission");
return;
}
// Already authenticated-check
if (data.Players.ContainsKey(player.Id))
{
Message(player, "Already Authenticated");
return;
}
// Sends the code if already exist to prevent duplication
if (Codes.ContainsKey(player.Id))
{
Message(player, "Code Generation", Codes[player.Id]);
return;
}
// Adds a random code and send it to the player if doesn't already exist
var code = GenerateCode(config.Code.CodeLength, config.Code.Lowercase);
Codes.Add(player.Id, code);
Message(player, "Code Generation", code);
// Code Expiration Function
timer.In(config.Code.CodeLifetime * 60, () =>
{
if (Codes.ContainsKey(player.Id))
{
Codes.Remove(player.Id);
if (player != null) Message(player, "Code Expired");
}
});
}
private void DeauthCommand(IPlayer player, string command, string[] args)
{
// No Permission
if (!player.HasPermission(deauthPerm))
{
Message(player, "No Permission");
return;
}
if (!data.Players.ContainsKey(player.Id))
{
Message(player, "Not Authenticated");
return;
}
Oxide.Ext.Discord.DiscordObjects.User.GetUser(Client, data.Players[player.Id], user => HandleRoles(user, MemberRole.Remove));
Deauthenticate(player.Id, data.Players[player.Id]);
Message(player, "Game-Deauthenticated");
}
#endregion
#region Oxide Hooks
private void Init()
{
data = Interface.Oxide.DataFileSystem.ReadObject<Data>(Name);
CreateClient();
AddCovalenceCommand(config.Info.AuthCommands, nameof(AuthCommand));
AddCovalenceCommand(config.Info.DeauthCommands, nameof(DeauthCommand));
permission.CreateGroup(config.Info.Group, config.Info.Group, 0);
permission.RegisterPermission(authPerm, this);
permission.RegisterPermission(deauthPerm, this);
if (!config.Info.Deauthenticate && !config.Info.RemovefromGroup)
Unsubscribe(nameof(Discord_MemberRemoved));
if (!config.Info.RemovefromGroup)
Unsubscribe(nameof(Discord_MemberAdded));
if (!config.Info.Log)
Unsubscribe(nameof(DiscordSocket_Initalized));
}
private void Unload()
{
CloseClient();
SaveData();
}
private void OnServerSave() => SaveData();
#endregion
#region Discord Hooks
// Called when a message is created on the Discord server
private void Discord_MessageCreate(Message message)
{
// Bot-check
if (message.author.bot == true)
return;
Channel.GetChannel(Client, message.channel_id, dm =>
{
// DM-check
if (dm.type != ChannelType.DM)
return;
// Length-check
if (message.content.Length != config.Code.CodeLength)
return;
// No code found
if (!Codes.ContainsValue(message.content))
{
dm.CreateMessage(Client, GetEmbed(Formatter.ToPlaintext(Lang("Unable to find code")), 16098851));
return;
}
// Already authenticated-check
if (data.Players.ContainsValue(message.author.id))
{
dm.CreateMessage(Client, GetEmbed(Formatter.ToPlaintext(Lang("Already Authenticated")), 4886754));
return;
}
Codes.Keys.ToList().ForEach(playerId =>
{
if (Codes[playerId] != message.content)
return;
Authenticate(playerId, message.author.id);
});
HandleRoles(message.author, MemberRole.Add);
dm.CreateMessage(Client, GetEmbed(Formatter.ToPlaintext(Lang("Authenticated")), 11523722));
});
}
// Called when a member leaves the Discord server
private void Discord_MemberRemoved(GuildMember member)
{
var steamId = API_GetSteam(member.user.id);
// No user found
if (steamId == null)
return;
if (config.Info.Deauthenticate)
{
Deauthenticate(steamId, member.user.id);
member.user.CreateDM(Client, dm => dm.CreateMessage(Client, GetEmbed(Formatter.ToPlaintext(Lang("Discord-Deauthenticated", steamId, Client.DiscordServer.name)), 9905970)));
return;
}
if (config.Info.RemovefromGroup)
{
permission.RemoveUserGroup(steamId, config.Info.Group);
member.user.CreateDM(Client, dm => dm.CreateMessage(Client, GetEmbed(Formatter.ToPlaintext(Lang("Group Revoked", steamId, config.Info.Group)), 16098851)));
}
}
// Called when a user joins the discord server
private void Discord_MemberAdded(GuildMember member)
{
var steamId = API_GetSteam(member.user.id);
// No user found
if (steamId == null)
return;
HandleRoles(member.user, MemberRole.Add);
permission.AddUserGroup(steamId, config.Info.Group);
member.user.CreateDM(Client, dm => dm.CreateMessage(Client, GetEmbed(Formatter.ToPlaintext(Lang("Group Granted", steamId, config.Info.Group, Client.DiscordServer.name)), 4886754)));
}
// Called when the client is created, and the plugin can use it
private void DiscordSocket_Initalized(DiscordClient client) => Puts("Discord Initalized!");
#endregion
#region Core
private void Authenticate(string steamId, string discordId)
{
if (Interface.Oxide.CallHook("OnAuthenticate", steamId, discordId) != null)
return;
data.Players.Add(steamId, discordId);
permission.AddUserGroup(steamId, config.Info.Group);
}
private void Deauthenticate(string steamId, string discordId)
{
if (Interface.Oxide.CallHook("OnDeauthenticate", steamId, discordId) != null)
return;
data.Players.Remove(steamId);
permission.RemoveUserGroup(steamId, config.Info.Group);
}
private void HandleRoles(Oxide.Ext.Discord.DiscordObjects.User user, MemberRole memberRole)
{
config.Info.Roles.ForEach(roleName =>
{
var role = GetRoleByName(roleName);
if (role == null)
{
PrintError($"Unable to find '{roleName}'");
return;
}
switch (memberRole)
{
case MemberRole.Add:
Client.DiscordServer.AddGuildMemberRole(Client, user, role);
break;
case MemberRole.Remove:
Client.DiscordServer.RemoveGuildMemberRole(Client, user, role);
break;
}
});
}
#endregion
#region API
//private bool API_Authenticate(string steamId, string discordId, bool addtoGroup = true, bool callHook = true)
//{
// if (!data.Players.ContainsKey(steamId) || !data.Players.ContainsValue(discordId))
// {
// if(addtoGroup)
// permission.AddUserGroup(steamId, config.Info.Group);
// if(callHook)
// Interface.Oxide.CallHook("OnAuthenticate", steamId, discordId);
// data.Players.Add(steamId, discordId);
// return true;
// }
// return false;
//}
//private bool API_Deauthenticate(string Id, bool removefromGroup = true, bool callHook = true)
//{
// // If Id is steamId
// if (data.Players.ContainsKey(Id))
// {
// if (removefromGroup)
// permission.RemoveUserGroup(Id, config.Info.Group);
// if (callHook)
// Interface.Oxide.CallHook("OnDeauthenticate", Id, data.Players[Id]);
// data.Players.Remove(Id);
// return true;
// }
// // If Id is discordId
// if (data.Players.ContainsValue(Id))
// {
// foreach (var steamid in data.Players.Keys)
// {
// if (data.Players[steamid] == Id)
// {
// if (removefromGroup)
// permission.RemoveUserGroup(steamid, config.Info.Group);
// if (callHook)
// Interface.Oxide.CallHook("OnDeauthenticate", steamid, Id);
// data.Players.Remove(steamid);
// return true;
// }
// }
// }
// return false;
//}
private bool API_IsAuthenticated(string Id)
{
if (data.Players.ContainsKey(Id))
return true;
if (data.Players.ContainsValue(Id))
return true;
return false;
}
private string API_GetSteam(string Id)
{
if (data.Players.ContainsValue(Id))
{
foreach (var steamid in data.Players.Keys)
{
if (data.Players[steamid] == Id)
return steamid;
}
}
return null;
}
private string API_GetDiscord(string Id)
{
if (data.Players.ContainsKey(Id))
{
return data.Players[Id];
}
return null;
}
private int API_GetAuthCount() => data.Players.Count;
private List<string> API_GetSteamList() => data.Players.Keys.ToList();
private List<string> API_GetDiscordList() => data.Players.Values.ToList();
#endregion
#region Helpers
private void CreateClient()
{
if (config.Info.BotToken != string.Empty)
Discord.CreateClient(this, config.Info.BotToken);
}
private void CloseClient() => Discord.CloseClient(Client);
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, data);
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private void Message(IPlayer player, string key, params object[] args) => player.Reply($"{config.Info.ChatPrefix} {Lang(key, player.Id, args)}");
private string GenerateCode(int size, bool lowerCase)
{
var builder = new StringBuilder();
var random = new System.Random();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
if (lowerCase)
return builder.ToString().ToLower();
return builder.ToString();
}
private Embed GetEmbed(string text, int color)
{
var embed = new Embed
{
description = text,
color = color
};
return embed;
}
private Role GetRoleByName(string roleName)
{
foreach (var role in Client.DiscordServer.roles)
{
if (role.name == roleName)
return role;
}
return null;
}
#endregion
}
}

721
plugins/GatherManager.cs Normal file
View File

@ -0,0 +1,721 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Gathering Manager", "Mughisi", "2.2.75", ResourceId = 675)]
class GatherManager : RustPlugin
{
#region Configuration Data
// Do not modify these values because this will not change anything, the values listed below are only used to create
// the initial configuration file. If you wish changes to the configuration file you should edit 'GatherManager.json'
// which is located in your server's config folder: <drive>:\...\server\<your_server_identity>\oxide\config\
private bool configChanged;
// Plugin settings
private const string DefaultChatPrefix = "Gather Manager";
private const string DefaultChatPrefixColor = "#008000ff";
public string ChatPrefix { get; private set; }
public string ChatPrefixColor { get; private set; }
// Plugin options
private static readonly Dictionary<string, object> DefaultGatherResourceModifiers = new Dictionary<string, object>();
private static readonly Dictionary<string, object> DefaultGatherDispenserModifiers = new Dictionary<string, object>();
private static readonly Dictionary<string, object> DefaultQuarryResourceModifiers = new Dictionary<string, object>();
private static readonly Dictionary<string, object> DefaultPickupResourceModifiers = new Dictionary<string, object>();
private static readonly Dictionary<string, object> DefaultSurveyResourceModifiers = new Dictionary<string, object>();
// Defaults
private const float DefaultMiningQuarryResourceTickRate = 5f;
private const float DefaultExcavatorResourceTickRate = 3f;
private const float DefaultExcavatorTimeForFullResources = 120f;
private const float DefaultExcavatorBeltSpeedMax = 0.1f;
public Dictionary<string, float> GatherResourceModifiers { get; private set; }
public Dictionary<string, float> GatherDispenserModifiers { get; private set; }
public Dictionary<string, float> QuarryResourceModifiers { get; private set; }
public Dictionary<string, float> ExcavatorResourceModifiers { get; private set; }
public Dictionary<string, float> PickupResourceModifiers { get; private set; }
public Dictionary<string, float> SurveyResourceModifiers { get; private set; }
public float MiningQuarryResourceTickRate { get; private set; }
public float ExcavatorResourceTickRate { get; private set; }
public float ExcavatorTimeForFullResources { get; private set; }
public float ExcavatorBeltSpeedMax { get; private set; }
// Plugin messages
private const string DefaultNotAllowed = "You don't have permission to use this command.";
private const string DefaultInvalidArgumentsGather =
"Invalid arguments supplied! Use gather.rate <type:dispenser|pickup|quarry|survey> <resource> <multiplier>";
private const string DefaultInvalidArgumentsDispenser =
"Invalid arguments supplied! Use dispenser.scale <dispenser:tree|ore|corpse> <multiplier>";
private const string DefaultInvalidArgumentsSpeed =
"Invalid arguments supplied! Use quarry.rate <time between gathers in seconds>";
private const string DefaultInvalidModifier =
"Invalid modifier supplied! The new modifier always needs to be bigger than 0!";
private const string DefaultInvalidSpeed = "You can't set the speed lower than 1 second!";
private const string DefaultModifyResource = "You have set the gather rate for {0} to x{1} from {2}.";
private const string DefaultModifyResourceRemove = "You have reset the gather rate for {0} from {1}.";
private const string DefaultModifySpeed = "The Mining Quarry will now provide resources every {0} seconds.";
private const string DefaultInvalidResource =
"{0} is not a valid resource. Check gather.resources for a list of available options.";
private const string DefaultModifyDispenser = "You have set the resource amount for {0} dispensers to x{1}";
private const string DefaultInvalidDispenser =
"{0} is not a valid dispenser. Check gather.dispensers for a list of available options.";
private const string DefaultHelpText = "/gather - Shows you detailed gather information.";
private const string DefaultHelpTextPlayer = "Resources gained from gathering have been scaled to the following:";
private const string DefaultHelpTextAdmin = "To change the resources gained by gathering use the command:\r\ngather.rate <type:dispenser|pickup|quarry|survey> <resource> <multiplier>\r\nTo change the amount of resources in a dispenser type use the command:\r\ndispenser.scale <dispenser:tree|ore|corpse> <multiplier>\r\nTo change the time between Mining Quarry gathers:\r\nquarry.tickrate <seconds>";
private const string DefaultHelpTextPlayerGains = "Resources gained from {0}:";
private const string DefaultHelpTextPlayerMiningQuarrySpeed = "Time between Mining Quarry gathers: {0} second(s).";
private const string DefaultHelpTextPlayerDefault = "Default values.";
private const string DefaultDispensers = "Resource Dispensers";
private const string DefaultCharges = "Survey Charges";
private const string DefaultQuarries = "Mining Quarries";
private const string DefaultExcavators = "Excavators";
private const string DefaultPickups = "pickups";
public string NotAllowed { get; private set; }
public string InvalidArgumentsGather { get; private set; }
public string InvalidArgumentsDispenser { get; private set; }
public string InvalidArgumentsSpeed { get; private set; }
public string InvalidModifier { get; private set; }
public string InvalidSpeed { get; private set; }
public string ModifyResource { get; private set; }
public string ModifyResourceRemove { get; private set; }
public string ModifySpeed { get; private set; }
public string InvalidResource { get; private set; }
public string ModifyDispenser { get; private set; }
public string InvalidDispenser { get; private set; }
public string HelpText { get; private set; }
public string HelpTextPlayer { get; private set; }
public string HelpTextAdmin { get; private set; }
public string HelpTextPlayerGains { get; private set; }
public string HelpTextPlayerDefault { get; private set; }
public string HelpTextPlayerMiningQuarrySpeed { get; private set; }
public string Dispensers { get; private set; }
public string Charges { get; private set; }
public string Quarries { get; private set; }
public string Excavators { get; private set; }
public string Pickups { get; private set; }
#endregion
private readonly List<string> subcommands = new List<string>() { "dispenser", "pickup", "quarry", "survey" };
private readonly Hash<string, ItemDefinition> validResources = new Hash<string, ItemDefinition>();
private readonly Hash<string, ResourceDispenser.GatherType> validDispensers = new Hash<string, ResourceDispenser.GatherType>();
private void Init() => LoadConfigValues();
private void OnServerInitialized()
{
var resourceDefinitions = ItemManager.itemList;
foreach (var def in resourceDefinitions.Where(def => def.category == ItemCategory.Food || def.category == ItemCategory.Resources))
validResources.Add(def.displayName.english.ToLower(), def);
validDispensers.Add("tree", ResourceDispenser.GatherType.Tree);
validDispensers.Add("ore", ResourceDispenser.GatherType.Ore);
validDispensers.Add("corpse", ResourceDispenser.GatherType.Flesh);
validDispensers.Add("flesh", ResourceDispenser.GatherType.Flesh);
foreach (var excavator in UnityEngine.Object.FindObjectsOfType<ExcavatorArm>())
{
if (ExcavatorResourceTickRate != DefaultMiningQuarryResourceTickRate)
{
excavator.CancelInvoke("ProcessResources");
excavator.InvokeRepeating("ProcessResources", ExcavatorResourceTickRate, ExcavatorResourceTickRate);
}
if (ExcavatorBeltSpeedMax != DefaultExcavatorBeltSpeedMax)
{
excavator.beltSpeedMax = ExcavatorBeltSpeedMax;
}
if (ExcavatorTimeForFullResources != DefaultExcavatorTimeForFullResources)
{
excavator.timeForFullResources = ExcavatorTimeForFullResources;
}
}
}
private void Unload()
{
foreach (var excavator in UnityEngine.Object.FindObjectsOfType<ExcavatorArm>())
{
if (ExcavatorResourceTickRate != DefaultMiningQuarryResourceTickRate)
{
excavator.CancelInvoke("ProcessResources");
excavator.InvokeRepeating("ProcessResources", DefaultMiningQuarryResourceTickRate, DefaultMiningQuarryResourceTickRate);
}
if (ExcavatorBeltSpeedMax != DefaultExcavatorBeltSpeedMax)
{
excavator.beltSpeedMax = DefaultExcavatorBeltSpeedMax;
}
if (ExcavatorTimeForFullResources != DefaultExcavatorTimeForFullResources)
{
excavator.timeForFullResources = DefaultExcavatorTimeForFullResources;
}
}
}
protected override void LoadDefaultConfig() => PrintWarning("New configuration file created.");
[ChatCommand("gather")]
private void Gather(BasePlayer player, string command, string[] args)
{
var help = HelpTextPlayer;
if (GatherResourceModifiers.Count == 0 && SurveyResourceModifiers.Count == 0 && PickupResourceModifiers.Count == 0 && QuarryResourceModifiers.Count == 0)
help += HelpTextPlayerDefault;
else
{
if (GatherResourceModifiers.Count > 0)
{
var dispensers = string.Format(HelpTextPlayerGains, Dispensers);
dispensers = GatherResourceModifiers.Aggregate(dispensers, (current, entry) => current + ("\r\n " + entry.Key + ": x" + entry.Value));
help += "\r\n" + dispensers;
}
if (PickupResourceModifiers.Count > 0)
{
var pickups = string.Format(HelpTextPlayerGains, Pickups);
pickups = PickupResourceModifiers.Aggregate(pickups, (current, entry) => current + ("\r\n " + entry.Key + ": x" + entry.Value));
help += "\r\n" + pickups;
}
if (QuarryResourceModifiers.Count > 0)
{
var quarries = string.Format(HelpTextPlayerGains, Quarries);
quarries = QuarryResourceModifiers.Aggregate(quarries, (current, entry) => current + ("\r\n " + entry.Key + ": x" + entry.Value));
help += "\r\n" + quarries;
}
if (ExcavatorResourceModifiers.Count > 0)
{
var excavators = string.Format(HelpTextPlayerGains, Excavators);
excavators = ExcavatorResourceModifiers.Aggregate(excavators, (current, entry) => current + ("\r\n " + entry.Key + ": x" + entry.Value));
help += "\r\n" + excavators;
}
if (SurveyResourceModifiers.Count > 0)
{
var charges = string.Format(HelpTextPlayerGains, Charges);
charges = SurveyResourceModifiers.Aggregate(charges, (current, entry) => current + ("\r\n " + entry.Key + ": x" + entry.Value));
help += "\r\n" + charges;
}
}
if (MiningQuarryResourceTickRate != DefaultMiningQuarryResourceTickRate)
help += "\r\n" + string.Format(HelpTextPlayerMiningQuarrySpeed, MiningQuarryResourceTickRate);
SendMessage(player, help);
if (!player.IsAdmin) return;
SendMessage(player, HelpTextAdmin);
}
private void SendHelpText(BasePlayer player) => SendMessage(player, HelpText);
[ConsoleCommand("gather.rate")]
private void GatherRate(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.Player().IsAdmin)
{
arg.ReplyWith(NotAllowed);
return;
}
var subcommand = arg.GetString(0).ToLower();
if (!arg.HasArgs(3) || !subcommands.Contains(subcommand))
{
arg.ReplyWith(InvalidArgumentsGather);
return;
}
if (!validResources[arg.GetString(1).ToLower()] && arg.GetString(1) != "*")
{
arg.ReplyWith(string.Format(InvalidResource, arg.GetString(1)));
return;
}
var resource = validResources[arg.GetString(1).ToLower()]?.displayName.english ?? "*";
var modifier = arg.GetFloat(2, -1);
var remove = false;
if (modifier < 0)
{
if (arg.GetString(2).ToLower() == "remove")
remove = true;
else
{
arg.ReplyWith(InvalidModifier);
return;
}
}
switch (subcommand)
{
case "dispenser":
if (remove)
{
if (GatherResourceModifiers.ContainsKey(resource))
GatherResourceModifiers.Remove(resource);
arg.ReplyWith(string.Format(ModifyResourceRemove, resource, Dispensers));
}
else
{
if (GatherResourceModifiers.ContainsKey(resource))
GatherResourceModifiers[resource] = modifier;
else
GatherResourceModifiers.Add(resource, modifier);
arg.ReplyWith(string.Format(ModifyResource, resource, modifier, Dispensers));
}
SetConfigValue("Options", "GatherResourceModifiers", GatherResourceModifiers);
break;
case "pickup":
if (remove)
{
if (PickupResourceModifiers.ContainsKey(resource))
PickupResourceModifiers.Remove(resource);
arg.ReplyWith(string.Format(ModifyResourceRemove, resource, Pickups));
}
else
{
if (PickupResourceModifiers.ContainsKey(resource))
PickupResourceModifiers[resource] = modifier;
else
PickupResourceModifiers.Add(resource, modifier);
arg.ReplyWith(string.Format(ModifyResource, resource, modifier, Pickups));
}
SetConfigValue("Options", "PickupResourceModifiers", PickupResourceModifiers);
break;
case "quarry":
if (remove)
{
if (QuarryResourceModifiers.ContainsKey(resource))
QuarryResourceModifiers.Remove(resource);
arg.ReplyWith(string.Format(ModifyResourceRemove, resource, Quarries));
}
else
{
if (QuarryResourceModifiers.ContainsKey(resource))
QuarryResourceModifiers[resource] = modifier;
else
QuarryResourceModifiers.Add(resource, modifier);
arg.ReplyWith(string.Format(ModifyResource, resource, modifier, Quarries));
}
SetConfigValue("Options", "QuarryResourceModifiers", QuarryResourceModifiers);
break;
case "excavator":
if (remove)
{
if (ExcavatorResourceModifiers.ContainsKey(resource))
ExcavatorResourceModifiers.Remove(resource);
arg.ReplyWith(string.Format(ModifyResourceRemove, resource, Excavators));
}
else
{
if (ExcavatorResourceModifiers.ContainsKey(resource))
ExcavatorResourceModifiers[resource] = modifier;
else
ExcavatorResourceModifiers.Add(resource, modifier);
arg.ReplyWith(string.Format(ModifyResource, resource, modifier, Excavators));
}
SetConfigValue("Options", "ExcavatorResourceModifiers", ExcavatorResourceModifiers);
break;
case "survey":
if (remove)
{
if (SurveyResourceModifiers.ContainsKey(resource))
SurveyResourceModifiers.Remove(resource);
arg.ReplyWith(string.Format(ModifyResourceRemove, resource, Charges));
}
else
{
if (SurveyResourceModifiers.ContainsKey(resource))
SurveyResourceModifiers[resource] = modifier;
else
SurveyResourceModifiers.Add(resource, modifier);
arg.ReplyWith(string.Format(ModifyResource, resource, modifier, Charges));
}
SetConfigValue("Options", "SurveyResourceModifiers", SurveyResourceModifiers);
break;
}
}
[ConsoleCommand("gather.resources")]
private void GatherResources(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.Player().IsAdmin)
{
arg.ReplyWith(NotAllowed);
return;
}
arg.ReplyWith(validResources.Aggregate("Available resources:\r\n", (current, resource) => current + (resource.Value.displayName.english + "\r\n")) + "* (For all resources that are not setup separately)");
}
[ConsoleCommand("gather.dispensers")]
private void GatherDispensers(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.Player().IsAdmin)
{
arg.ReplyWith(NotAllowed);
return;
}
arg.ReplyWith(validDispensers.Aggregate("Available dispensers:\r\n", (current, dispenser) => current + (dispenser.Value.ToString("G") + "\r\n")));
}
[ConsoleCommand("dispenser.scale")]
private void DispenserRate(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.Player().IsAdmin)
{
arg.ReplyWith(NotAllowed);
return;
}
if (!arg.HasArgs(2))
{
arg.ReplyWith(InvalidArgumentsDispenser);
return;
}
if (!validDispensers.ContainsKey(arg.GetString(0).ToLower()))
{
arg.ReplyWith(string.Format(InvalidDispenser, arg.GetString(0)));
return;
}
var dispenser = validDispensers[arg.GetString(0).ToLower()].ToString("G");
var modifier = arg.GetFloat(1, -1);
if (modifier < 0)
{
arg.ReplyWith(InvalidModifier);
return;
}
if (GatherDispenserModifiers.ContainsKey(dispenser))
GatherDispenserModifiers[dispenser] = modifier;
else
GatherDispenserModifiers.Add(dispenser, modifier);
SetConfigValue("Options", "GatherDispenserModifiers", GatherDispenserModifiers);
arg.ReplyWith(string.Format(ModifyDispenser, dispenser, modifier));
}
[ConsoleCommand("quarry.tickrate")]
private void MiningQuarryTickRate(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.Player().IsAdmin)
{
arg.ReplyWith(NotAllowed);
return;
}
if (!arg.HasArgs())
{
arg.ReplyWith(InvalidArgumentsSpeed);
return;
}
var modifier = arg.GetFloat(0, -1);
if (modifier < 1)
{
arg.ReplyWith(InvalidSpeed);
return;
}
MiningQuarryResourceTickRate = modifier;
SetConfigValue("Options", "MiningQuarryResourceTickRate", MiningQuarryResourceTickRate);
arg.ReplyWith(string.Format(ModifySpeed, modifier));
var quarries = UnityEngine.Object.FindObjectsOfType<MiningQuarry>();
foreach (var quarry in quarries.Where(quarry => quarry.IsOn()))
{
quarry.CancelInvoke("ProcessResources");
quarry.InvokeRepeating("ProcessResources", MiningQuarryResourceTickRate, MiningQuarryResourceTickRate);
}
}
[ConsoleCommand("excavator.tickrate")]
private void ExcavatorTickRate(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !arg.Player().IsAdmin)
{
arg.ReplyWith(NotAllowed);
return;
}
if (!arg.HasArgs())
{
arg.ReplyWith(InvalidArgumentsSpeed);
return;
}
var modifier = arg.GetFloat(0, -1);
if (modifier < 1)
{
arg.ReplyWith(InvalidSpeed);
return;
}
ExcavatorResourceTickRate = modifier;
SetConfigValue("Options", "ExcavatorResourceTickRate", ExcavatorResourceTickRate);
arg.ReplyWith(string.Format(ModifySpeed, modifier));
var excavators = UnityEngine.Object.FindObjectsOfType<MiningQuarry>();
foreach (var excavator in excavators.Where(excavator => excavator.IsOn()))
{
excavator.CancelInvoke("ProcessResources");
excavator.InvokeRepeating("ProcessResources", ExcavatorResourceTickRate, ExcavatorResourceTickRate);
}
}
private void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item)
{
if (!entity.ToPlayer())
{
return;
}
var gatherType = dispenser.gatherType.ToString("G");
var amount = item.amount;
float modifier;
if (GatherResourceModifiers.TryGetValue(item.info.displayName.english, out modifier))
{
item.amount = (int)(item.amount * modifier);
}
else if (GatherResourceModifiers.TryGetValue("*", out modifier))
{
item.amount = (int)(item.amount * modifier);
}
if (!GatherResourceModifiers.ContainsKey(gatherType))
{
return;
}
var dispenserModifier = GatherDispenserModifiers[gatherType];
try
{
dispenser.containedItems.Single(x => x.itemid == item.info.itemid).amount += amount - item.amount / dispenserModifier;
if (dispenser.containedItems.Single(x => x.itemid == item.info.itemid).amount < 0)
{
item.amount += (int)dispenser.containedItems.Single(x => x.itemid == item.info.itemid).amount;
}
}
catch { }
}
private void OnDispenserBonus(ResourceDispenser dispenser, BaseEntity entity, Item item)
{
OnDispenserGather(dispenser, entity, item);
}
private void OnGrowableGathered(GrowableEntity growable, Item item, BasePlayer player)
{
float modifier;
if ( GatherResourceModifiers.TryGetValue(item.info.displayName.english, out modifier) )
{
item.amount = (int)(item.amount * modifier);
}
else if ( GatherResourceModifiers.TryGetValue("*", out modifier) )
{
item.amount = (int)(item.amount * modifier);
}
}
private void OnQuarryGather(MiningQuarry quarry, Item item)
{
float modifier;
if (QuarryResourceModifiers.TryGetValue(item.info.displayName.english, out modifier))
{
item.amount = (int)(item.amount * modifier);
}
else if (QuarryResourceModifiers.TryGetValue("*", out modifier))
{
item.amount = (int)(item.amount * modifier);
}
}
private void OnExcavatorGather(ExcavatorArm excavator, Item item)
{
float modifier;
if (ExcavatorResourceModifiers.TryGetValue(item.info.displayName.english, out modifier))
{
item.amount = (int)(item.amount * modifier);
}
else if (ExcavatorResourceModifiers.TryGetValue("*", out modifier))
{
item.amount = (int)(item.amount * modifier);
}
}
private void OnCollectiblePickup(Item item, BasePlayer player)
{
float modifier;
if (PickupResourceModifiers.TryGetValue(item.info.displayName.english, out modifier))
{
item.amount = (int)(item.amount * modifier);
}
else if (PickupResourceModifiers.TryGetValue("*", out modifier))
{
item.amount = (int)(item.amount * modifier);
}
}
private void OnSurveyGather(SurveyCharge surveyCharge, Item item)
{
float modifier;
if (SurveyResourceModifiers.TryGetValue(item.info.displayName.english, out modifier))
{
item.amount = (int)(item.amount * modifier);
}
else if (SurveyResourceModifiers.TryGetValue("*", out modifier))
{
item.amount = (int)(item.amount * modifier);
}
}
private void OnMiningQuarryEnabled(MiningQuarry quarry)
{
if (MiningQuarryResourceTickRate == DefaultMiningQuarryResourceTickRate) return;
quarry.CancelInvoke("ProcessResources");
quarry.InvokeRepeating("ProcessResources", MiningQuarryResourceTickRate, MiningQuarryResourceTickRate);
}
private void LoadConfigValues()
{
// Plugin settings
ChatPrefix = GetConfigValue("Settings", "ChatPrefix", DefaultChatPrefix);
ChatPrefixColor = GetConfigValue("Settings", "ChatPrefixColor", DefaultChatPrefixColor);
// Plugin options
var gatherResourceModifiers = GetConfigValue("Options", "GatherResourceModifiers", DefaultGatherResourceModifiers);
var gatherDispenserModifiers = GetConfigValue("Options", "GatherDispenserModifiers", DefaultGatherDispenserModifiers);
var quarryResourceModifiers = GetConfigValue("Options", "QuarryResourceModifiers", DefaultQuarryResourceModifiers);
var excavatorResourceModifiers = GetConfigValue("Options", "ExcavatorResourceModifiers", quarryResourceModifiers);
var pickupResourceModifiers = GetConfigValue("Options", "PickupResourceModifiers", DefaultPickupResourceModifiers);
var surveyResourceModifiers = GetConfigValue("Options", "SurveyResourceModifiers", DefaultSurveyResourceModifiers);
MiningQuarryResourceTickRate = GetConfigValue("Options", "MiningQuarryResourceTickRate", DefaultMiningQuarryResourceTickRate);
ExcavatorResourceTickRate = GetConfigValue("Options", "ExcavatorResourceTickRate", DefaultExcavatorResourceTickRate);
ExcavatorBeltSpeedMax = GetConfigValue("Options", "ExcavatorBeltSpeedMax", DefaultExcavatorBeltSpeedMax);
ExcavatorTimeForFullResources = GetConfigValue("Options", "ExcavatorTimeForFullResources", DefaultExcavatorTimeForFullResources);
GatherResourceModifiers = new Dictionary<string, float>();
foreach (var entry in gatherResourceModifiers)
{
float rate;
if (!float.TryParse(entry.Value.ToString(), out rate)) continue;
GatherResourceModifiers.Add(entry.Key, rate);
}
GatherDispenserModifiers = new Dictionary<string, float>();
foreach (var entry in gatherDispenserModifiers)
{
float rate;
if (!float.TryParse(entry.Value.ToString(), out rate)) continue;
GatherDispenserModifiers.Add(entry.Key, rate);
}
QuarryResourceModifiers = new Dictionary<string, float>();
foreach (var entry in quarryResourceModifiers)
{
float rate;
if (!float.TryParse(entry.Value.ToString(), out rate)) continue;
QuarryResourceModifiers.Add(entry.Key, rate);
}
ExcavatorResourceModifiers = new Dictionary<string, float>();
foreach (var entry in excavatorResourceModifiers)
{
float rate;
if (!float.TryParse(entry.Value.ToString(), out rate)) continue;
ExcavatorResourceModifiers.Add(entry.Key, rate);
}
PickupResourceModifiers = new Dictionary<string, float>();
foreach (var entry in pickupResourceModifiers)
{
float rate;
if (!float.TryParse(entry.Value.ToString(), out rate)) continue;
PickupResourceModifiers.Add(entry.Key, rate);
}
SurveyResourceModifiers = new Dictionary<string, float>();
foreach (var entry in surveyResourceModifiers)
{
float rate;
if (!float.TryParse(entry.Value.ToString(), out rate)) continue;
SurveyResourceModifiers.Add(entry.Key, rate);
}
// Plugin messages
NotAllowed = GetConfigValue("Messages", "NotAllowed", DefaultNotAllowed);
InvalidArgumentsGather = GetConfigValue("Messages", "InvalidArgumentsGather", DefaultInvalidArgumentsGather);
InvalidArgumentsDispenser = GetConfigValue("Messages", "InvalidArgumentsDispenserType", DefaultInvalidArgumentsDispenser);
InvalidArgumentsSpeed = GetConfigValue("Messages", "InvalidArgumentsMiningQuarrySpeed", DefaultInvalidArgumentsSpeed);
InvalidModifier = GetConfigValue("Messages", "InvalidModifier", DefaultInvalidModifier);
InvalidSpeed = GetConfigValue("Messages", "InvalidMiningQuarrySpeed", DefaultInvalidSpeed);
ModifyResource = GetConfigValue("Messages", "ModifyResource", DefaultModifyResource);
ModifyResourceRemove = GetConfigValue("Messages", "ModifyResourceRemove", DefaultModifyResourceRemove);
ModifySpeed = GetConfigValue("Messages", "ModifyMiningQuarrySpeed", DefaultModifySpeed);
InvalidResource = GetConfigValue("Messages", "InvalidResource", DefaultInvalidResource);
ModifyDispenser = GetConfigValue("Messages", "ModifyDispenser", DefaultModifyDispenser);
InvalidDispenser = GetConfigValue("Messages", "InvalidDispenser", DefaultInvalidDispenser);
HelpText = GetConfigValue("Messages", "HelpText", DefaultHelpText);
HelpTextAdmin = GetConfigValue("Messages", "HelpTextAdmin", DefaultHelpTextAdmin);
HelpTextPlayer = GetConfigValue("Messages", "HelpTextPlayer", DefaultHelpTextPlayer);
HelpTextPlayerGains = GetConfigValue("Messages", "HelpTextPlayerGains", DefaultHelpTextPlayerGains);
HelpTextPlayerDefault = GetConfigValue("Messages", "HelpTextPlayerDefault", DefaultHelpTextPlayerDefault);
HelpTextPlayerMiningQuarrySpeed = GetConfigValue("Messages", "HelpTextMiningQuarrySpeed", DefaultHelpTextPlayerMiningQuarrySpeed);
Dispensers = GetConfigValue("Messages", "Dispensers", DefaultDispensers);
Quarries = GetConfigValue("Messages", "MiningQuarries", DefaultQuarries);
Excavators = GetConfigValue("Messages", "Excavators", DefaultExcavators);
Charges = GetConfigValue("Messages", "SurveyCharges", DefaultCharges);
Pickups = GetConfigValue("Messages", "Pickups", DefaultPickups);
if (!configChanged) return;
PrintWarning("Configuration file updated.");
SaveConfig();
}
private T GetConfigValue<T>(string category, string setting, T defaultValue)
{
var data = Config[category] as Dictionary<string, object>;
object value;
if (data == null)
{
data = new Dictionary<string, object>();
Config[category] = data;
configChanged = true;
}
if (data.TryGetValue(setting, out value)) return (T)Convert.ChangeType(value, typeof(T));
value = defaultValue;
data[setting] = value;
configChanged = true;
return (T)Convert.ChangeType(value, typeof(T));
}
private void SetConfigValue<T>(string category, string setting, T newValue)
{
var data = Config[category] as Dictionary<string, object>;
object value;
if (data != null && data.TryGetValue(setting, out value))
{
value = newValue;
data[setting] = value;
configChanged = true;
}
SaveConfig();
}
private void SendMessage(BasePlayer player, string message, params object[] args) => player?.SendConsoleCommand("chat.add", 0, -1, string.Format($"<color={ChatPrefixColor}>{ChatPrefix}</color>: {message}", args), 1.0);
}
}

1282
plugins/ImageLibrary.cs Normal file

File diff suppressed because it is too large Load Diff

422
plugins/InventoryViewer.cs Normal file
View File

@ -0,0 +1,422 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Inventory Viewer", "Mughisi", "3.0.3", ResourceId = 871)]
[Description("Allows players with permission assigned to view anyone's inventory")]
public class InventoryViewer : RustPlugin
{
private readonly string RequiredPermission = "inventoryviewer.allowed";
private readonly Dictionary<BasePlayer, List<BasePlayer>> matches = new Dictionary<BasePlayer, List<BasePlayer>>();
/// <summary>
/// UnityEngine script to be attached to the player viewing someone's inventory.
/// </summary>
private class Inspector : MonoBehaviour
{
/// <summary>
/// The player doing the inspecting.
/// </summary>
private BasePlayer player;
/// <summary>
/// The player being inspected.
/// </summary>
private BasePlayer target;
/// <summary>
/// The tick counter used by the Inspector.
/// </summary>
private int ticks;
/// <summary>
/// Instantiates the Inspector script.
/// </summary>
public void Instantiate(BasePlayer player, BasePlayer target)
{
this.player = player;
this.target = target;
BeginLooting();
InvokeRepeating("UpdateLoot", 0f, 0.1f);
}
/// <summary>
/// Updates the loot.
/// </summary>
private void UpdateLoot()
{
if (!target)
{
return;
}
if (!target.inventory)
{
return;
}
ticks++;
if (!player.inventory.loot.IsLooting())
{
BeginLooting();
}
player.inventory.loot.SendImmediate();
player.SendNetworkUpdateImmediate();
}
/// <summary>
/// Stops inspecting.
/// </summary>
private void StopInspecting(bool forced = false)
{
if (ticks < 5 && !forced)
{
return;
}
CancelInvoke("UpdateLoot");
EndLooting();
}
/// <summary>
/// Starts the looting.
/// </summary>
private void BeginLooting()
{
player.inventory.loot.Clear();
if (!target)
{
return;
}
if (!target.inventory)
{
return;
}
player.inventory.loot.AddContainer(target.inventory.containerMain);
player.inventory.loot.AddContainer(target.inventory.containerWear);
player.inventory.loot.AddContainer(target.inventory.containerBelt);
player.inventory.loot.PositionChecks = false;
player.inventory.loot.entitySource = target;
player.inventory.loot.itemSource = null;
player.inventory.loot.MarkDirty();
player.inventory.loot.SendImmediate();
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "player_corpse");
player.SendNetworkUpdateImmediate();
}
/// <summary>
/// Ends the looting.
/// </summary>
private void EndLooting()
{
player.inventory.loot.MarkDirty();
if (player.inventory.loot.entitySource)
{
player.inventory.loot.entitySource.SendMessage("PlayerStoppedLooting", player, SendMessageOptions.DontRequireReceiver);
}
foreach (ItemContainer container in player.inventory.loot.containers)
{
if (container != null)
{
container.onDirty -= player.inventory.loot.MarkDirty;
}
}
player.inventory.loot.containers.Clear();
player.inventory.loot.entitySource = null;
player.inventory.loot.itemSource = null;
}
/// <summary>
/// Destroys the script
/// </summary>
public void Remove(bool forced = false)
{
if (ticks < 5 && !forced)
{
return;
}
StopInspecting(forced);
Destroy(this);
}
}
/// <summary>
/// Oxide hook that is triggered when the plugin is loaded.
/// </summary>
private void Loaded()
{
permission.RegisterPermission(RequiredPermission, this);
}
/// <summary>
/// Oxide hook that is triggered after the plugin is loaded to setup localized messages.
/// </summary>
private new void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
{ "InvalidArguments", "Invalid argument(s) supplied! Use '/{0} <name>' or '/{0} list <number>'." },
{ "InvalidSelection", "Invalid number, use the number in front of the player's name. Use '/{0} list' to check the list of players again." },
{ "MultiplePlayersFound", "Multiple players found with that name, please select one of these players by using '/{0} list <number>':" },
{ "NoListAvailable", "You do not have a players list available, use '/{0} <name>' instead." },
{ "NoPlayersFound", "Couldn't find any players matching that name." },
{ "NotAllowed", "You are not allowed to use this command." },
{ "TooManyPlayersFound", "Too many players were found, the list of matches is only showing the first 5. Try to be more specific." }
}, this);
}
/// <summary>
/// Oxide hook that is triggered when the plugin is unloaded.
/// </summary>
private void Unload()
{
Inspector[] inspectors = UnityEngine.Object.FindObjectsOfType<Inspector>();
foreach (Inspector inspector in inspectors)
inspector.Remove();
}
/// <summary>
/// Oxide hook that is triggered when a console command is executed.
/// </summary>
private void OnServerCommand(ConsoleSystem.Arg arg)
{
if (arg.cmd.FullName == "inventory.endloot")
{
BasePlayer player = arg.Player();
player.GetComponent<Inspector>()?.Remove();
}
}
/// <summary>
/// Oxide hook that is triggered when a player attempts to loot another player
/// </summary>
private object CanLootPlayer(BasePlayer target, BasePlayer looter)
{
if (looter.GetComponent<Inspector>() == null)
{
return null;
}
return true;
}
/// <summary>
/// Handles the /inspect command
/// </summary>
[ChatCommand("inspect")]
private void InspectCommand(BasePlayer player, string command, string[] args)
{
ViewInventoryCommand(player, command, args);
}
/// <summary>
/// Handles the /viewinv command
/// </summary>
[ChatCommand("viewinv")]
private void ViewInvCommand(BasePlayer player, string command, string[] args)
{
ViewInventoryCommand(player, command, args);
}
/// <summary>
/// Handles the /viewinventory command
/// </summary>
[ChatCommand("viewinventory")]
private void ViewInventoryCommand(BasePlayer player, string command, string[] args)
{
if (!CanUseCommand(player))
{
SendChatMessage(player, "NotAllowed");
return;
}
if (args.Length < 1)
{
SendChatMessage(player, "InvalidArguments", command);
return;
}
if (args[0] == "list")
{
if (args.Length == 1)
{
if (!matches.ContainsKey(player) || matches[player] == null)
{
SendChatMessage(player, "NoListAvailable", command);
return;
}
ShowMatches(player);
return;
}
int num;
if (int.TryParse(args[1], out num))
{
if (!matches.ContainsKey(player) || matches[player] == null)
{
SendChatMessage(player, "NoListAvailable", command);
return;
}
if (num > matches[player].Count)
{
SendChatMessage(player, "InvalidSelection", command);
ShowMatches(player);
return;
}
StartInspecting(player, matches[player][num - 1]);
return;
}
SendChatMessage(player, "InvalidArguments", command);
}
else
{
string name = string.Join(" ", args);
List<BasePlayer> players = FindPlayersByNameOrId(name);
switch (players.Count)
{
case 0:
SendChatMessage(player, "NoPlayersFound", command);
break;
case 1:
StartInspecting(player, players[0]);
break;
default:
SendChatMessage(player, "MultiplePlayersFound", command);
if (!matches.ContainsKey(player))
{
matches.Add(player, players);
}
else
{
matches[player] = players;
}
ShowMatches(player);
break;
}
}
}
/// <summary>
/// Looks up all players (active and sleeping) by a given (partial) name or steam id.
/// </summary>
private List<BasePlayer> FindPlayersByNameOrId(string nameOrId)
{
List<BasePlayer> matches = new List<BasePlayer>();
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (!string.IsNullOrEmpty(player.displayName))
{
if (player.displayName.ToLower().Contains(nameOrId.ToLower()))
{
matches.Add(player);
}
}
if (player.UserIDString == nameOrId)
{
matches.Add(player);
}
}
foreach (BasePlayer player in BasePlayer.sleepingPlayerList)
{
if (!string.IsNullOrEmpty(player.displayName))
{
if (player.displayName.ToLower().Contains(nameOrId.ToLower()))
{
matches.Add(player);
}
}
if (player.UserIDString == nameOrId)
{
matches.Add(player);
}
}
return matches.OrderBy(p => p.displayName).ToList();
}
/// <summary>
/// Shows the cached matches for the player.
/// </summary>
private void ShowMatches(BasePlayer player)
{
for (int i = 0; i < matches[player].Count; i++)
{
SendChatMessage(player, $"{i + 1}. {matches[player][i].displayName}");
if (i == 4 && i < matches[player].Count)
{
SendChatMessage(player, "TooManyPlayersFound");
break;
}
}
}
/// <summary>
/// Initializes the inspector for the given player and target.
/// </summary>
private void StartInspecting(BasePlayer player, BasePlayer target)
{
Inspector inspector = player.gameObject.GetComponent<Inspector>();
inspector?.Remove();
inspector = player.gameObject.AddComponent<Inspector>();
inspector.Instantiate(player, target);
}
/// <summary>
/// Checks if the specified BasePlayer has the required permission.
/// </summary>
private bool CanUseCommand(BasePlayer player)
{
return permission.UserHasPermission(player.UserIDString, RequiredPermission);
}
/// <summary>
/// Sends a localized chat message using the key to the specified player
/// </summary>
private void SendChatMessage(BasePlayer player, string key, params string[] args)
{
if (args == null || args.Length == 0)
{
Player.Reply(player, lang.GetMessage(key, this, player.UserIDString));
}
else
{
Player.Reply(player, string.Format(lang.GetMessage(key, this, player.UserIDString), args));
}
}
}
}

1979
plugins/Kits.cs Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,875 @@
using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core.Plugins;
using Oxide.Core.Libraries;
using Oxide.Game.Rust.Cui;
using Newtonsoft.Json;
//Fixed next/previous/back navigation memory.
//now handles group names with spaces
namespace Oxide.Plugins
{
[Info("PermissionsManager", "Steenamaroo", "2.0.4", ResourceId = 0)]
class PermissionsManager : RustPlugin
{
#region Declarations
List<string> PlugList = new List<string>();
Dictionary<int, string> numberedPerms = new Dictionary<int, string>();
List<ulong> MenuOpen = new List<ulong>();
bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
const string permAllowed = "permissionsmanager.allowed";
Dictionary<ulong, Info> ActiveAdmins = new Dictionary<ulong, Info>();
public class Info
{
public string inheritedcheck = "";
public int noOfPlugs;
public int pluginPage = 1;
public int PPage = 1;
public int GPage = 1;
public string subjectGroup;
public BasePlayer subject;
}
string ButtonColour1 = "0.7 0.32 0.17 1";
string ButtonColour2 = "0.2 0.2 0.2 1";
#endregion
#region Hooks
void OnPluginLoaded(Plugin plugin)
{
if (plugin is PermissionsManager)
return;
Wipe();
OnServerInitialized();
}
void OnPluginUnloaded(Plugin plugin)
{
if (plugin is PermissionsManager)
return;
Wipe();
OnServerInitialized();
}
void Loaded()
{
lang.RegisterMessages(messages, this);
permission.RegisterPermission(permAllowed, this);
}
void OnServerInitialized()
{
foreach (BasePlayer player in BasePlayer.activePlayerList.Where(player => MenuOpen.Contains(player.userID)))
DestroyMenu(player, true);
if (!LoadConfigVariables())
{
Puts("Config file issue detected. Please delete file, or check syntax and fix.");
return;
}
SaveConfig();
}
void Unload()
{
foreach (BasePlayer player in BasePlayer.activePlayerList.Where(player => MenuOpen.Contains(player.userID)))
DestroyMenu(player, true);
}
void OnPlayerDisconnected(BasePlayer player)
{
if (MenuOpen.Contains(player.userID))
DestroyMenu(player, true);
}
void OnPlayerDeath(BasePlayer player, HitInfo info)
{
if (MenuOpen.Contains(player.userID))
DestroyMenu(player, true);
}
#endregion
#region Methods
void DestroyMenu(BasePlayer player, bool all)
{
CuiHelper.DestroyUi(player, "PMMainUI");
CuiHelper.DestroyUi(player, "PMPermsUI");
CuiHelper.DestroyUi(player, "PMConfirmUI");
if (all)
{
CuiHelper.DestroyUi(player, "PMBgUI");
MenuOpen.Remove(player.userID);
}
}
void Wipe()
{
PlugList.Clear();
numberedPerms.Clear();
}
void GetPlugs(BasePlayer player)
{
var path = ActiveAdmins[player.userID];
PlugList.Clear();
path.noOfPlugs = 0;
foreach (var entry in plugins.GetAll())
{
if (entry.IsCorePlugin)
continue;
var str = entry.ToString();
var charsToRemove = new string[] { "Oxide.Plugins." };
foreach (var c in charsToRemove)
str = str.Replace(c, string.Empty).ToLower();
foreach (var perm in permission.GetPermissions().ToList().Where(perm => perm.Contains($"{str}") && !(config.BlockList.Split(',').ToList().Contains($"{str}"))))
if (!PlugList.Contains(str))
PlugList.Add(str);
}
PlugList.Sort();
}
bool IsAuth(BasePlayer player) => player?.net?.connection != null && player.net.connection.authLevel == 2;
void SetButtons(bool on)
{
ButtonColour1 = (on) ? config.OffColour : config.OnColour;
ButtonColour2 = (on) ? config.OnColour : config.OffColour;
}
object[] PermsCheck(BasePlayer player, string group, string info)
{
bool has = false;
List<string> inherited = new List<string>();
var path = ActiveAdmins[player.userID];
if (group == "true")
{
if (permission.GroupHasPermission(path.subjectGroup, info))
has = true;
}
else
{
UserData userData = permission.GetUserData(path.subject.UserIDString);
if (userData.Perms.Contains(info))
has = true;
foreach (var group1 in permission.GetUserGroups(path.subject.UserIDString))
if (permission.GroupHasPermission(group1, info))
inherited.Add(group1);
}
return new object[] { has, inherited };
}
#endregion
#region UI
void PMBgUI(BasePlayer player)
{
MenuOpen.Add(player.userID);
string guiString = String.Format("0.1 0.1 0.1 {0}", config.guitransparency);
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel { Image = { Color = guiString }, RectTransform = { AnchorMin = "0.3 0.1", AnchorMax = "0.7 0.9" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "PMBgUI");
elements.Add(new CuiButton { Button = { Color = "0 0 0 1" }, RectTransform = { AnchorMin = $"0 0.95", AnchorMax = $"0.998 1" }, Text = { Text = String.Empty } }, mainName);
elements.Add(new CuiButton { Button = { Color = "0 0 0 1" }, RectTransform = { AnchorMin = $"0 0", AnchorMax = $"0.998 0.05" }, Text = { Text = String.Empty } }, mainName);
elements.Add(new CuiButton { Button = { Command = "ClosePM", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.955 0.96", AnchorMax = "0.99 0.995" }, Text = { Text = "X", FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
CuiHelper.AddUi(player, elements);
}
void PMMainUI(BasePlayer player, bool group, int page)
{
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel { Image = { Color = "0 0 0 0" }, RectTransform = { AnchorMin = "0.32 0.1", AnchorMax = "0.68 0.9" }, CursorEnabled = true }, "Overlay", "PMMainUI");
elements.Add(new CuiElement { Parent = "PMMainUI", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
string subject = (group) ? lang.GetMessage("GUIPlayers", this) : lang.GetMessage("GUIGroups", this);
string current = (!group) ? lang.GetMessage("GUIPlayers", this) : lang.GetMessage("GUIGroups", this);
elements.Add(new CuiLabel { Text = { Text = "Permissions Manager V2", FontSize = 16, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.95", AnchorMax = "1 1" } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"PMTogglePlayerGroup {group} 1", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.04" }, Text = { Text = lang.GetMessage("All", this) + " " + subject, FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
int pos1 = 20 - (page * 20), quantity = 0;
float top = 0.87f;
float bottom = 0.85f;
elements.Add(new CuiLabel { Text = { Text = lang.GetMessage("All", this) + " " + current, FontSize = 14, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.9", AnchorMax = "1 0.97" } }, mainName);
if (group)
foreach (var grp in permission.GetGroups())
{
pos1++;
quantity++;
if (pos1 > 0 && pos1 < 21)
{
elements.Add(new CuiButton { Button = { Command = $"PMSelected group {grp}", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.3 {bottom}", AnchorMax = $"0.7 {top}" }, Text = { Text = $"{grp}", FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
top = top - 0.025f;
bottom = bottom - 0.025f;
}
}
else
foreach (var plyr in GetAllPlayers())
{
pos1++;
quantity++;
if (pos1 > 0 && pos1 < 21)
{
elements.Add(new CuiButton { Button = { Command = $"PMSelected player {plyr.userID}", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.3 {bottom}", AnchorMax = $"0.7 {top}" }, Text = { Text = $"{plyr.displayName}", FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
top = top - 0.025f;
bottom = bottom - 0.025f;
}
}
if (quantity > (page * 20))
elements.Add(new CuiButton { Button = { Command = $"PMTogglePlayerGroup {!group} {page + 1}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.8 0.02", AnchorMax = "0.9 0.04" }, Text = { Text = lang.GetMessage("->", this), FontSize = 11, Align = TextAnchor.MiddleCenter }, }, mainName);
if (page > 1)
elements.Add(new CuiButton { Button = { Command = $"PMTogglePlayerGroup {!group} {page - 1}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.1 0.02", AnchorMax = "0.2 0.04" }, Text = { Text = lang.GetMessage("<-", this), FontSize = 11, Align = TextAnchor.MiddleCenter }, }, mainName);
CuiHelper.AddUi(player, elements);
}
void PlugsUI(BasePlayer player, string msg, string group, int page)
{
var path = ActiveAdmins[player.userID];
var backpage = group == "false" ? path.PPage : path.GPage;
string toggle = (group == "true") ? "false" : "true";
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel { Image = { Color = "0 0 0 0" }, RectTransform = { AnchorMin = "0.32 0.1", AnchorMax = "0.68 0.9" }, CursorEnabled = true }, "Overlay", "PMPermsUI");
elements.Add(new CuiElement { Parent = "PMPermsUI", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
int plugsTotal = 0, pos1 = 60 - (page * 60), next = page + 1, previous = page - 1;
for (int i = 0; i < PlugList.Count; i++)
{
pos1++;
plugsTotal++;
if (pos1 > 0 && pos1 < 21)
elements.Add(new CuiButton { Button = { Command = $"PermsList {i} null null {group} null 1", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.1 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.3 {0.91 - (pos1 * 3f) / 100f}" }, Text = { Text = $"{PlugList[i]}", FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
if (pos1 > 20 && pos1 < 41)
elements.Add(new CuiButton { Button = { Command = $"PermsList {i} null null {group} null 1", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.4 {(0.89 - ((pos1 - 20) * 3f) / 100f)}", AnchorMax = $"0.6 {0.91 - ((pos1 - 20) * 3f) / 100f}" }, Text = { Text = $"{PlugList[i]}", FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
if (pos1 > 40 && pos1 < 61)
elements.Add(new CuiButton { Button = { Command = $"PermsList {i} null null {group} null 1", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.7 {(0.89 - ((pos1 - 40) * 3f) / 100f)}", AnchorMax = $"0.9 {0.91 - ((pos1 - 40) * 3f) / 100f}" }, Text = { Text = $"{PlugList[i]}", FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
}
elements.Add(new CuiButton { Button = { Command = $"PMTogglePlayerGroup {toggle} {backpage}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.55 0.02", AnchorMax = "0.75 0.04" }, Text = { Text = lang.GetMessage("GUIBack", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiLabel { Text = { Text = msg, FontSize = 16, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.95", AnchorMax = "1 1" } }, mainName);
if (group == "false")
elements.Add(new CuiButton { Button = { Command = "Groups 1", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.25 0.02", AnchorMax = "0.45 0.04" }, Text = { Text = lang.GetMessage("GUIGroups", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
else
elements.Add(new CuiButton { Button = { Command = "PlayersIn 1", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.25 0.02", AnchorMax = "0.45 0.04" }, Text = { Text = lang.GetMessage("GUIPlayers", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
if (plugsTotal > (page * 60))
elements.Add(new CuiButton { Button = { Command = $"Navigate {group} {next}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.8 0.02", AnchorMax = "0.9 0.04" }, Text = { Text = lang.GetMessage("->", this), FontSize = 11, Align = TextAnchor.MiddleCenter }, }, mainName);
if (page > 1)
elements.Add(new CuiButton { Button = { Command = $"Navigate {group} {previous}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.1 0.02", AnchorMax = "0.2 0.04" }, Text = { Text = lang.GetMessage("<-", this), FontSize = 11, Align = TextAnchor.MiddleCenter }, }, mainName);
CuiHelper.AddUi(player, elements);
}
void PMPermsUI(BasePlayer player, string msg, int PlugNumber, string group, int page)
{
var path = ActiveAdmins[player.userID];
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel { Image = { Color = "0 0 0 0" }, RectTransform = { AnchorMin = "0.32 0.1", AnchorMax = "0.68 0.9" }, CursorEnabled = true }, "Overlay", "PMPermsUI");
elements.Add(new CuiElement { Parent = "PMPermsUI", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
int permsTotal = 0, pos1 = 20 - (page * 20), next = (page + 1), previous = (page - 1);
elements.Add(new CuiButton { Button = { Command = $"PermsList {PlugNumber} grant null {group} all {page}", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.5 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.6 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUIAll", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"PermsList {PlugNumber} revoke null {group} all {page}", Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.65 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.75 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUINone", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
var elements1 = new CuiElementContainer();
bool list = false;
foreach (var perm in numberedPerms)
{
SetButtons(true);
pos1++;
permsTotal++;
var permNo = perm.Key;
string showName = numberedPerms[permNo];
string output = showName.Substring(showName.IndexOf('.') + 1);
string granted = lang.GetMessage("GUIGranted", this);
if (pos1 > 0 && pos1 < 21)
{
granted = lang.GetMessage("GUIGranted", this);
if ((bool)PermsCheck(player, group, numberedPerms[permNo])[0])
SetButtons(false);
List<string> inheritcheck = (List<string>)(PermsCheck(player, group, numberedPerms[permNo])[1]);
if (inheritcheck.Count > 0)
{
if (path.inheritedcheck == numberedPerms[permNo])
{
var mainName1 = elements1.Add(new CuiPanel { Image = { Color = "0.1 0.1 0.1 0.99" }, RectTransform = { AnchorMin = "0.3 0.1", AnchorMax = "0.7 0.86" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "PMConfirmUI");
elements1.Add(new CuiButton { Button = { Command = $"ShowInherited {PlugNumber} null {numberedPerms[permNo]} {group} null {page} -", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.4 0.01", AnchorMax = "0.6 0.05" }, Text = { Text = lang.GetMessage("GUIBack", this), FontSize = 14, Align = TextAnchor.MiddleCenter }, }, mainName1);
float h1 = 0, h2 = 0;
elements1.Add(new CuiButton { Button = { Command = "", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.3 0.8", AnchorMax = "0.7 0.825" }, Text = { Text = $"{numberedPerms[permNo]}", FontSize = 12, Align = TextAnchor.MiddleCenter }, }, mainName1);
elements1.Add(new CuiLabel { Text = { Text = $"{lang.GetMessage("GUIInheritedFrom", this)}", FontSize = 11, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.77", AnchorMax = "1 0.8" } }, mainName1);
for (int i = 0; i < inheritcheck.Count; i++)
{
h1 = i * 0.022f;
h2 = i * 0.022f;
elements1.Add(new CuiLabel { Text = { Text = $"{inheritcheck[i]}", FontSize = 11, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = $"0 {0.7 - h1}", AnchorMax = $"1 {0.75 - h2}" } }, mainName1);
}
list = true;
}
elements.Add(new CuiButton { Button = { Command = $"ShowInherited {PlugNumber} null {numberedPerms[permNo]} {group} null {page} {numberedPerms[permNo]}", Color = config.InheritedColour }, RectTransform = { AnchorMin = $"0.8 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.9 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUIInherited", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
}
elements.Add(new CuiButton { Button = { Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.1 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.45 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = $"{output}", FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"PermsList {PlugNumber} grant {numberedPerms[permNo]} {group} null {page}", Color = ButtonColour1 }, RectTransform = { AnchorMin = $"0.5 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.6 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUIGranted", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"PermsList {PlugNumber} revoke {numberedPerms[permNo]} {group} null {page}", Color = ButtonColour2 }, RectTransform = { AnchorMin = $"0.65 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.75 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUIRevoked", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
}
}
elements.Add(new CuiButton { Button = { Command = $"Navigate {group} {path.pluginPage}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.04" }, Text = { Text = lang.GetMessage("GUIBack", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiLabel { Text = { Text = msg, FontSize = 16, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.95", AnchorMax = "1 1" } }, mainName);
if (permsTotal > (page * 20))
elements.Add(new CuiButton { Button = { Command = $"PermsList {PlugNumber} null null {group} null {next}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.8 0.02", AnchorMax = "0.9 0.04" }, Text = { Text = "->", FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
if (page > 1)
elements.Add(new CuiButton { Button = { Command = $"PermsList {PlugNumber} null null {group} null {previous}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.1 0.02", AnchorMax = "0.2 0.04" }, Text = { Text = "<-", FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
CuiHelper.AddUi(player, elements);
if (list)
CuiHelper.AddUi(player, elements1);
}
void ViewPlayersUI(BasePlayer player, string msg, int page)
{
var path = ActiveAdmins[player.userID];
var outmsg = string.Format(lang.GetMessage("GUIPlayersIn", this), msg);
string guiString = String.Format("0.1 0.1 0.1 {0}", config.guitransparency);
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel { Image = { Color = "0 0 0 0" }, RectTransform = { AnchorMin = "0.32 0.1", AnchorMax = "0.68 0.9" }, CursorEnabled = true }, "Overlay", "PMPermsUI");
elements.Add(new CuiElement { Parent = "PMPermsUI", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
int playerCounter = 0, pos1 = 20 - (page * 20), next = page + 1, previous = page - 1;
foreach (var useringroup in permission.GetUsersInGroup(path.subjectGroup))
{
pos1++;
playerCounter++;
if (pos1 > 0 && pos1 < 21)
elements.Add(new CuiButton { Button = { Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.2 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.8 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = $"{useringroup}", FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
}
elements.Add(new CuiLabel { Text = { Text = outmsg, FontSize = 16, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.95", AnchorMax = "1 1" } }, mainName);
if (playerCounter > (page * 20))
elements.Add(new CuiButton { Button = { Command = $"PlayersIn {next}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.8 0.02", AnchorMax = "0.9 0.04" }, Text = { Text = lang.GetMessage("->", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
if (page > 1)
elements.Add(new CuiButton { Button = { Command = $"PlayersIn {previous}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.1 0.02", AnchorMax = "0.2 0.04" }, Text = { Text = lang.GetMessage("<-", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"PMEmptyGroup", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.25 0.02", AnchorMax = "0.45 0.04" }, Text = { Text = lang.GetMessage("removePlayers", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"Navigate true {path.PPage}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.55 0.02", AnchorMax = "0.75 0.04" }, Text = { Text = lang.GetMessage("GUIBack", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
CuiHelper.AddUi(player, elements);
}
void ViewGroupsUI(BasePlayer player, string msg, int page)
{
var path = ActiveAdmins[player.userID];
var outmsg = string.Format(lang.GetMessage("GUIGroupsFor", this), msg);
string guiString = String.Format("0.1 0.1 0.1 {0}", config.guitransparency);
var elements = new CuiElementContainer();
var mainName = elements.Add(new CuiPanel { Image = { Color = "0 0 0 0" }, RectTransform = { AnchorMin = "0.32 0.1", AnchorMax = "0.68 0.9" }, CursorEnabled = true }, "Overlay", "PMPermsUI");
elements.Add(new CuiElement { Parent = "PMPermsUI", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
int groupTotal = 0, pos1 = 20 - (page * 20), next = page + 1, previous = page - 1;
foreach (var group in permission.GetGroups())
{
SetButtons(true);
pos1++;
groupTotal++;
if (pos1 > 0 && pos1 < 21)
{
foreach (var user in permission.GetUsersInGroup(group))
{
if (user.Contains(path.subject.UserIDString))
{
SetButtons(false);
break;
}
}
//MAKE THIS OPEN UI FOR THAT GROUP
elements.Add(new CuiButton { Button = { Color = config.ButtonColour }, RectTransform = { AnchorMin = $"0.2 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.5 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = $"{group}", FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"GroupAddRemove add {RemoveSpaces(group)} {page}", Color = ButtonColour1 }, RectTransform = { AnchorMin = $"0.55 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.65 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUIGranted", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiButton { Button = { Command = $"GroupAddRemove remove {RemoveSpaces(group)} {page}", Color = ButtonColour2 }, RectTransform = { AnchorMin = $"0.7 {(0.89 - (pos1 * 3f) / 100f)}", AnchorMax = $"0.8 {(0.91 - (pos1 * 3f) / 100f)}" }, Text = { Text = lang.GetMessage("GUIRevoked", this), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
}
}
elements.Add(new CuiButton { Button = { Command = $"Navigate false {path.pluginPage}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.04" }, Text = { Text = lang.GetMessage("GUIBack", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
elements.Add(new CuiLabel { Text = { Text = outmsg, FontSize = 16, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.95", AnchorMax = "1 1" } }, mainName);
if (groupTotal > (page * 20))
elements.Add(new CuiButton { Button = { Command = $"Groups {next}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.7 0.02", AnchorMax = "0.8 0.04" }, Text = { Text = lang.GetMessage("->", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
if (page > 1)
elements.Add(new CuiButton { Button = { Command = $"Groups {previous}", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.2 0.02", AnchorMax = "0.3 0.04" }, Text = { Text = lang.GetMessage("<-", this), FontSize = 11, Align = TextAnchor.MiddleCenter } }, mainName);
CuiHelper.AddUi(player, elements);
}
#endregion
#region console commands
[ConsoleCommand("PMToMain")]
private void PMToMain(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
PMMainUI(player, false, 1);
}
[ConsoleCommand("PMTogglePlayerGroup")]
private void PMTogglePlayerGroup(ConsoleSystem.Arg arg, bool group, int page)
{
var player = arg?.Connection?.player as BasePlayer;
if (player == null || arg.Args == null || arg.Args.Length != 2) return;
group = !(Convert.ToBoolean(arg.Args[0]));
page = Convert.ToInt16(arg.Args[1]);
if (group)
ActiveAdmins[player.userID].GPage = page;
else
ActiveAdmins[player.userID].PPage = page;
DestroyMenu(player, false);
PMMainUI(player, group, page);
}
[ConsoleCommand("ShowInherited")]
private void ShowInherited(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
if (player == null || arg.Args == null || arg.Args.Length < 6) return;
int pageNo = Convert.ToInt32(arg.Args[5]);
path.inheritedcheck = arg.Args[6];
var plugNumber = Convert.ToInt32(arg.Args[0]);
string plugName = PlugList[Convert.ToInt32(arg.Args[0])];
DestroyMenu(player, false);
PMPermsUI(player, $"{path.subject.displayName} - {plugName}", plugNumber, "false", pageNo);
}
[ConsoleCommand("PMEmptyGroup")]
private void PMEmptyGroup(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var elements1 = new CuiElementContainer();
var mainName1 = elements1.Add(new CuiPanel { Image = { Color = "0.1 0.1 0.1 0.8" }, RectTransform = { AnchorMin = "0.4 0.42", AnchorMax = "0.6 0.48" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "PMConfirmUI");
elements1.Add(new CuiElement { Parent = "PMConfirmUI", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
elements1.Add(new CuiButton { Button = { Command = $"Empty true", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.1 0.2", AnchorMax = "0.4 0.8" }, Text = { Text = lang.GetMessage("confirm", this), FontSize = 14, Align = TextAnchor.MiddleCenter }, }, mainName1);
elements1.Add(new CuiButton { Button = { Command = $"Empty false", Color = config.ButtonColour }, RectTransform = { AnchorMin = "0.6 0.2", AnchorMax = "0.9 0.8" }, Text = { Text = lang.GetMessage("cancel", this), FontSize = 14, Align = TextAnchor.MiddleCenter }, }, mainName1);
CuiHelper.AddUi(player, elements1);
}
[ConsoleCommand("EmptyGroup")]//user console command
private void EmptyGroup(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
if (player != null && !HasPermission(player.UserIDString, permAllowed) & !IsAuth(player))
{
SendReply(player, config.TitleColour + lang.GetMessage("title", this) + "</color>" + config.MessageColour + lang.GetMessage("NotAdmin", this) + "</color>");
return;
}
if (arg.Args == null || arg.Args.Length < 1)
return;
string groupname = arg.Args[0];
var list = permission.GetUsersInGroup(groupname);
if (list == null || list.Length == 0)
{
Puts($"Group {groupname} was not found.");
return;
}
foreach (var user in permission.GetUsersInGroup(groupname))
{
string str = user.Substring(0, 17);
permission.RemoveUserGroup(str, groupname);
}
Puts($"All users were removed from {groupname}");
}
[ConsoleCommand("Empty")]
private void Empty(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
string confirmation = arg.Args[0];
if (confirmation == "true")
{
int count = 0;
foreach (var user in permission.GetUsersInGroup(path.subjectGroup))
{
count++;
string str = user.Substring(0, 17);
permission.RemoveUserGroup(str, path.subjectGroup);
DestroyMenu(player, false);
var argsOut = new string[] { "group", path.subjectGroup };
CmdPerms(player, null, argsOut);
}
if (count == 0)
CuiHelper.DestroyUi(player, "PMConfirmUI");
}
else
CuiHelper.DestroyUi(player, "PMConfirmUI");
}
string RemoveSpaces(string input)=>input.Replace(" ", "-");
string RemoveDashes(string input)=>input.Replace("-", " ");
[ConsoleCommand("GroupAddRemove")]
private void GroupAddRemove(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
if (player == null || arg.Args == null || arg.Args.Length < 3) return;
string Pname = path.subject.userID.ToString();
string userGroup = RemoveDashes(arg.Args[1]);
int page = Convert.ToInt32(arg.Args[2]);
if (arg.Args[0] == "add")
permission.AddUserGroup(Pname, userGroup);
if (arg.Args[0] == "remove")
permission.RemoveUserGroup(Pname, userGroup);
DestroyMenu(player, false);
ViewGroupsUI(player, $"{path.subject.displayName}", page);
}
[ConsoleCommand("Groups")]
private void GroupsPM(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
if (player == null || arg.Args == null || arg.Args.Length < 1) return;
ActiveAdmins[player.userID].GPage = Convert.ToInt32(arg.Args[0]);
DestroyMenu(player, false);
ViewGroupsUI(player, $"{path.subject.displayName}", path.GPage);
}
[ConsoleCommand("PlayersIn")]
private void PlayersPM(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
if (player == null || arg.Args == null || arg.Args.Length < 1) return;
ActiveAdmins[player.userID].PPage = Convert.ToInt32(arg.Args[0]);
DestroyMenu(player, false);
ViewPlayersUI(player, $"{path.subjectGroup}", path.PPage);
}
[ConsoleCommand("ClosePM")]
private void ClosePM(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
if (player == null) return;
ActiveAdmins.Remove(player.userID);
DestroyMenu(player, true);
}
[ConsoleCommand("Navigate")]
private void Navigate(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
if (player == null || arg.Args == null || arg.Args.Length < 2) return;
ActiveAdmins[player.userID].pluginPage = Convert.ToInt32(arg.Args[1]);
DestroyMenu(player, false);
string[] argsOut;
if (arg.Args[0] == "true")
{
argsOut = new string[] { "group", path.subjectGroup, path.pluginPage.ToString() };
CmdPerms(player, null, argsOut);
}
else
{
argsOut = new string[] { "player", path.subject.userID.ToString(), path.pluginPage.ToString() };
CmdPerms(player, null, argsOut);
}
return;
}
[ConsoleCommand("PMSelected")]
private void PMSelected(ConsoleSystem.Arg arg)
{
var player = arg?.Connection?.player as BasePlayer;
DestroyMenu(player, false);
string[] argsOut;
argsOut = new string[] { arg.Args[0], arg.Args[1] };
if (arg.Args[0] == "player")
ActiveAdmins[player.userID].subject = FindPlayer(Convert.ToUInt64(arg.Args[1]));
else
ActiveAdmins[player.userID].subjectGroup = arg.Args[1];
CmdPerms(player, null, argsOut);
return;
}
[ConsoleCommand("PermsList")]
private void PermsList(ConsoleSystem.Arg arg, int plugNumber)
{
var player = arg?.Connection?.player as BasePlayer;
var path = ActiveAdmins[player.userID];
if (player == null || arg.Args == null || arg.Args.Length < 6) return;
int pageNo = Convert.ToInt32(arg.Args[5]);
string Pname;
string group = arg.Args[3];
if (arg.Args[4] == "all")
{
if (arg.Args[2] != null)
{
Pname = path.subject?.userID.ToString();
string action = arg.Args[1];
foreach (var perm in numberedPerms)
{
if (config.AllPerPage == true && perm.Key > (pageNo * 20) - 20 && perm.Key < ((pageNo * 20) + 1))
{
if (action == "grant" && group == "false")
permission.GrantUserPermission(Pname, perm.Value, null);
if (action == "revoke" && group == "false")
permission.RevokeUserPermission(Pname, perm.Value);
if (action == "grant" && group == "true")
permission.GrantGroupPermission(path.subjectGroup, perm.Value, null);
if (action == "revoke" && group == "true")
permission.RevokeGroupPermission(path.subjectGroup, perm.Value);
}
if (config.AllPerPage == false)
{
if (action == "grant" && group == "false")
permission.GrantUserPermission(Pname, perm.Value, null);
if (action == "revoke" && group == "false")
permission.RevokeUserPermission(Pname, perm.Value);
if (action == "grant" && group == "true")
permission.GrantGroupPermission(path.subjectGroup, perm.Value, null);
if (action == "revoke" && group == "true")
permission.RevokeGroupPermission(path.subjectGroup, perm.Value);
}
}
}
}
else
{
Pname = path.subject?.userID.ToString();
string action = arg.Args[1];
string PermInHand = arg.Args[2];
if (arg.Args[2] != null)
{
if (action == "grant" && group == "false")
permission.GrantUserPermission(Pname, PermInHand, null);
if (action == "revoke" && group == "false")
permission.RevokeUserPermission(Pname, PermInHand);
if (action == "grant" && group == "true")
permission.GrantGroupPermission(path.subjectGroup, PermInHand, null);
if (action == "revoke" && group == "true")
permission.RevokeGroupPermission(path.subjectGroup, PermInHand);
}
}
plugNumber = Convert.ToInt32(arg.Args[0]);
string plugName = PlugList[plugNumber];
numberedPerms.Clear();
int numOfPerms = 0;
foreach (var perm in permission.GetPermissions())
{
if (perm.Contains($"{plugName}."))
{
numOfPerms++;
numberedPerms.Add(numOfPerms, perm);
}
}
DestroyMenu(player, false);
if (group == "false")
PMPermsUI(player, $"{path.subject.displayName} - {plugName}", plugNumber, group, pageNo);
else
PMPermsUI(player, $"{path.subjectGroup} - {plugName}", plugNumber, group, pageNo);
return;
}
#endregion
#region chat commands
[ChatCommand("perms")]
void CmdPerms(BasePlayer player, string command, string[] args)
{
if (!HasPermission(player.UserIDString, permAllowed) & !IsAuth(player))
{
SendReply(player, config.TitleColour + lang.GetMessage("title", this) + "</color>" + config.MessageColour + lang.GetMessage("NotAdmin", this) + "</color>");
return;
}
if (!ActiveAdmins.ContainsKey(player.userID))
ActiveAdmins.Add(player.userID, new Info());
var path = ActiveAdmins[player.userID];
GetPlugs(player);
int page = 1;
if (args.Length == 3)
page = Convert.ToInt32(args[2]);
if (args == null || args.Length < 2)
{
bool group = (args != null && args.Length == 1 && args[0] == "group") ? true : false;
if (MenuOpen.Contains(player.userID))
DestroyMenu(player, group);
PMBgUI(player);
PMMainUI(player, group, 1);
return;
}
if (args[0] == "player")
{
UInt64 n = 0;
bool isNumeric = UInt64.TryParse(args[1], out n);
path.subject = isNumeric ? FindPlayer(n) : FindPlayerByName(args[1]);
if (path.subject == null)
{
SendReply(player, config.TitleColour + lang.GetMessage("title", this) + "</color>" + config.MessageColour + lang.GetMessage("NoPlayer", this) + "</color>", args[1]);
return;
}
string msg = string.Format(lang.GetMessage("GUIName", this), path.subject.displayName);
if (MenuOpen.Contains(player.userID))
DestroyMenu(player, true);
PMBgUI(player);
PlugsUI(player, msg, "false", page);
}
else if (args[0] == "group")
{
List<string> Groups = new List<string>();
foreach (var group in permission.GetGroups())
Groups.Add(group);
if (Groups.Contains($"{args[1]}"))
{
string msg = string.Format(lang.GetMessage("GUIName", this), args[1]);
ActiveAdmins[player.userID].subjectGroup = args[1];
if (MenuOpen.Contains(player.userID))
DestroyMenu(player, true);
PMBgUI(player);
PlugsUI(player, msg, "true", page);
return;
}
SendReply(player, config.TitleColour + lang.GetMessage("title", this) + "</color>" + config.MessageColour + lang.GetMessage("NoGroup", this) + "</color>", args[1]);
}
else
SendReply(player, config.TitleColour + lang.GetMessage("title", this) + "</color>" + config.MessageColour + lang.GetMessage("Syntax", this) + "</color>");
}
List<BasePlayer> GetAllPlayers()
{
List<BasePlayer> available = new List<BasePlayer>();
foreach (BasePlayer online in BasePlayer.activePlayerList)
available.Add(online);
foreach (BasePlayer sleeper in BasePlayer.sleepingPlayerList)
available.Add(sleeper);
return available;
}
BasePlayer FindPlayer(ulong ID)
{
BasePlayer result = null;
foreach (BasePlayer current in GetAllPlayers())
{
if (current.userID == ID)
result = current;
}
return result;
}
BasePlayer FindPlayerByName(string name)
{
BasePlayer result = null;
foreach (var player in GetAllPlayers())
{
if (player.displayName.Equals(name, StringComparison.OrdinalIgnoreCase)
|| player.UserIDString.Contains(name, CompareOptions.OrdinalIgnoreCase)
|| player.displayName.Contains(name, CompareOptions.OrdinalIgnoreCase))
result = player;
}
return result;
}
#endregion
#region config
public ConfigData config;
public class ConfigData
{
[JsonProperty(PropertyName = "Options - GUI Transparency 0-1")]
public double guitransparency = 0.9;
[JsonProperty(PropertyName = "Chat - Title colour")]
public string TitleColour = "<color=orange>";
[JsonProperty(PropertyName = "Chat - Message colour")]
public string MessageColour = "<color=white>";
[JsonProperty(PropertyName = "Options - Plugin BlockList")]
public string BlockList = "";
[JsonProperty(PropertyName = "GUI - Label colour")]
public string ButtonColour = "0.7 0.32 0.17 1";
[JsonProperty(PropertyName = "GUI - On colour")]
public string OnColour = "0.7 0.32 0.17 1";
[JsonProperty(PropertyName = "GUI - Off colour")]
public string OffColour = "0.2 0.2 0.2 1";
[JsonProperty(PropertyName = "GUI - All = per page")]
public bool AllPerPage = false;
[JsonProperty(PropertyName = "GUI - Inherited colour")]
public string InheritedColour = "0.9 0.6 0.17 1";
}
private bool LoadConfigVariables()
{
try
{
config = Config.ReadObject<ConfigData>();
}
catch
{
return false;
}
SaveConfig(config);
return true;
}
protected override void LoadDefaultConfig()
{
Puts("Creating new config file.");
var config = new ConfigData();
SaveConfig(config);
}
void SaveConfig(ConfigData config) => Config.WriteObject(config, true);
#endregion
#region messages
readonly Dictionary<string, string> messages = new Dictionary<string, string>()
{
{"title", "Permissions Manager: " },
{"NoGroup", "Group {0} was not found." },
{"NoPlayer", "Player {0} was not found." },
{"GUIAll", "Grant All" },
{"GUINone", "Revoke All" },
{"GUIBack", "Back" },
{"GUIGroups", "Groups" },
{"GUIPlayers", "Players" },
{"GUIInherited", "Inherited" },
{"GUIInheritedFrom", "Inherited from" },
{"GUIGranted", "Granted" },
{"GUIRevoked", "Revoked" },
{"GUIName", "Permissions for {0}" },
{"GUIGroupsFor", "Groups for {0}"},
{"GUIPlayersIn", "Players in {0}"},
{"removePlayers", "Remove All Players"},
{"confirm", "Confirm"},
{"cancel", "Cancel"},
{"NotAdmin", "You need Auth Level 2, or permission, to use this command."},
{"Back", "Back"},
{"All", "All"},
{"Syntax", "Use /perms, /perms player *name*, or /perms group *name*"}
};
#endregion
}
}

File diff suppressed because it is too large Load Diff

519
plugins/QuickSmelt.cs Normal file
View File

@ -0,0 +1,519 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins
{
[Info("Quick Smelt", "Iv Misticos", "5.1.3")]
[Description("Increases the speed of the furnace smelting")]
class QuickSmelt : RustPlugin
{
#region Variables
private static QuickSmelt _instance;
private const string PermissionUse = "quicksmelt.use";
#endregion
#region Configuration
private static Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Use Permission")]
public bool UsePermission = true;
[JsonProperty(PropertyName = "Speed Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> SpeedMultipliers = new Dictionary<string, float>
{
{"global", 1.0f},
{"furnace.shortname", 1.0f}
};
[JsonProperty(PropertyName = "Fuel Usage Speed Multipliers",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> FuelSpeedMultipliers = new Dictionary<string, float>
{
{"global", 1.0f},
{"furnace.shortname", 1.0f}
};
[JsonProperty(PropertyName = "Fuel Usage Multipliers",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> FuelUsageMultipliers = new Dictionary<string, int>
{
{"global", 1},
{"furnace.shortname", 1}
};
[JsonProperty(PropertyName = "Output Multipliers", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, Dictionary<string, float>> OutputMultipliers =
new Dictionary<string, Dictionary<string, float>>
{
{
"global", new Dictionary<string, float>
{
{"global", 1.0f}
}
},
{
"furnace.shortname", new Dictionary<string, float>
{
{"item.shortname", 1.0f}
}
}
};
[JsonProperty(PropertyName = "Whitelist", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<string>> Whitelist = new Dictionary<string, List<string>>
{
{
"global", new List<string>
{
"item.shortname"
}
},
{
"furnace.shortname", new List<string>
{
"item.shortname"
}
}
};
[JsonProperty(PropertyName = "Blacklist", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<string>> Blacklist = new Dictionary<string, List<string>>
{
{
"global", new List<string>
{
"item.shortname"
}
},
{
"furnace.shortname", new List<string>
{
"item.shortname"
}
}
};
[JsonProperty(PropertyName = "Smelting Frequencies (Smelt items every N smelting ticks)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> SmeltingFrequencies = new Dictionary<string, int>
{
{"global", 1},
{"furnace.shortname", 1}
};
[JsonProperty(PropertyName = "Debug")]
public bool Debug = false;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
}
catch
{
PrintError("Your configuration file contains an error. Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig() => _config = new Configuration();
protected override void SaveConfig() => Config.WriteObject(_config);
#endregion
#region Hooks
private void Unload()
{
var ovens = UnityEngine.Object.FindObjectsOfType<BaseOven>();
PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");
for (var i = 0; i < ovens.Length; i++)
{
var oven = ovens[i];
var component = oven.GetComponent<FurnaceController>();
if (oven.IsOn())
{
PrintDebug("Oven is on. Restarted cooking");
component.StopCooking();
oven.StartCooking();
}
UnityEngine.Object.Destroy(component);
}
PrintDebug("Done.");
}
private void OnServerInitialized()
{
_instance = this;
permission.RegisterPermission(PermissionUse, this);
var ovens = UnityEngine.Object.FindObjectsOfType<BaseOven>();
PrintDebug($"Processing BaseOven(s).. Amount: {ovens.Length}.");
for (var i = 0; i < ovens.Length; i++)
{
var oven = ovens[i];
OnEntitySpawned(oven);
}
timer.Once(1f, () =>
{
for (var i = 0; i < ovens.Length; i++)
{
var oven = ovens[i];
var component = oven.gameObject.GetComponent<FurnaceController>();
if (oven == null || oven.IsDestroyed || !oven.IsOn() || !CanUse(oven.OwnerID))
continue;
component.StartCooking();
}
});
}
private void OnEntitySpawned(BaseNetworkable entity)
{
var oven = entity as BaseOven;
if (oven == null)
return;
oven.gameObject.AddComponent<FurnaceController>();
}
private object OnOvenToggle(StorageContainer oven, BasePlayer player)
{
if (oven is BaseFuelLightSource || oven.needsBuildingPrivilegeToUse && !player.CanBuild())
return null;
PrintDebug("OnOvenToggle called");
var component = oven.gameObject.GetComponent<FurnaceController>();
var canUse = CanUse(oven.OwnerID) || CanUse(player.userID);
if (oven.IsOn())
{
component.StopCooking();
}
else
{
if (canUse)
component.StartCooking();
else
{
PrintDebug($"No permission ({player.userID})");
return null;
}
}
return false;
}
#endregion
#region Helpers
private bool CanUse(ulong id) =>
!_config.UsePermission || permission.UserHasPermission(id.ToString(), PermissionUse);
private static void PrintDebug(string message)
{
if (_config.Debug)
Debug.Log($"DEBUG ({_instance.Name}) > " + message);
}
#endregion
#region Controller
public class FurnaceController : FacepunchBehaviour
{
private int _ticks;
private BaseOven _oven;
private BaseOven Furnace
{
get
{
if (_oven == null)
_oven = GetComponent<BaseOven>();
return _oven;
}
}
private float _speedMultiplier;
private float _fuelSpeedMultiplier;
private int _fuelUsageMultiplier;
private int _smeltingFrequency;
private Dictionary<string, float> _outputModifiers;
private float OutputMultiplier(string shortname)
{
float modifier;
if (_outputModifiers == null || !_outputModifiers.TryGetValue(shortname, out modifier) &&
!_outputModifiers.TryGetValue("global", out modifier))
modifier = 1.0f;
PrintDebug($"{shortname} modifier: {modifier}");
return modifier;
}
private List<string> _blacklist;
private List<string> _whitelist;
private bool? IsAllowed(string shortname)
{
if (_blacklist != null && _blacklist.Contains(shortname))
return false;
if (_whitelist != null && _whitelist.Contains(shortname))
return true;
return null;
}
private void Awake()
{
// Well, sorry for my complicated code. But that should work faster! :)
float modifierF; // float modifier
int modifierI; // int modifier
if (!_config.SpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierF) &&
!_config.SpeedMultipliers.TryGetValue("global", out modifierF))
modifierF = 1.0f;
_speedMultiplier = 0.5f / modifierF;
if (!_config.FuelSpeedMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierF) &&
!_config.FuelSpeedMultipliers.TryGetValue("global", out modifierF))
modifierF = 1.0f;
_fuelSpeedMultiplier = modifierF;
if (!_config.FuelUsageMultipliers.TryGetValue(Furnace.ShortPrefabName, out modifierI) &&
!_config.FuelUsageMultipliers.TryGetValue("global", out modifierI))
modifierI = 1;
_fuelUsageMultiplier = modifierI;
if (!_config.SmeltingFrequencies.TryGetValue(Furnace.ShortPrefabName, out modifierI) &&
!_config.SmeltingFrequencies.TryGetValue("global", out modifierI))
modifierI = 1;
_smeltingFrequency = modifierI;
if (!_config.OutputMultipliers.TryGetValue(Furnace.ShortPrefabName, out _outputModifiers) && !_config.OutputMultipliers.TryGetValue("global", out _outputModifiers))
{
// ignored
}
if ((!_config.Blacklist.TryGetValue(Furnace.ShortPrefabName, out _blacklist) &&
!_config.Blacklist.TryGetValue("global", out _blacklist)) &
(!_config.Whitelist.TryGetValue(Furnace.ShortPrefabName, out _whitelist) &&
!_config.Whitelist.TryGetValue("global", out _whitelist)))
{
// ignored
}
}
private Item FindBurnable()
{
if (Furnace.inventory == null)
return null;
foreach (var item in Furnace.inventory.itemList)
{
var component = item.info.GetComponent<ItemModBurnable>();
if (component && (Furnace.fuelType == null || item.info == Furnace.fuelType))
{
return item;
}
}
return null;
}
public void Cook()
{
var item = FindBurnable();
if (item == null)
{
StopCooking();
return;
}
SmeltItems();
var slot = Furnace.GetSlot(BaseEntity.Slot.FireMod);
if (slot)
{
slot.SendMessage("Cook", 0.5f, SendMessageOptions.DontRequireReceiver);
}
var component = item.info.GetComponent<ItemModBurnable>();
item.fuel -= 0.5f * (Furnace.cookingTemperature / 200f) * _fuelSpeedMultiplier;
if (!item.HasFlag(global::Item.Flag.OnFire))
{
item.SetFlag(global::Item.Flag.OnFire, true);
item.MarkDirty();
}
if (item.fuel <= 0f)
{
ConsumeFuel(item, component);
}
_ticks++;
}
private void ConsumeFuel(Item fuel, ItemModBurnable burnable)
{
if (Furnace.allowByproductCreation && burnable.byproductItem != null && Random.Range(0f, 1f) > burnable.byproductChance)
{
var def = burnable.byproductItem;
var item = ItemManager.Create(def, (int) (burnable.byproductAmount * OutputMultiplier(def.shortname))); // It's fuel multiplier
if (!item.MoveToContainer(Furnace.inventory))
{
StopCooking();
item.Drop(Furnace.inventory.dropPosition, Furnace.inventory.dropVelocity);
}
}
if (fuel.amount <= 1)
{
fuel.Remove();
return;
}
fuel.amount -= _fuelUsageMultiplier;
fuel.fuel = burnable.fuelAmount;
fuel.MarkDirty();
}
private void SmeltItems()
{
if (_ticks % _smeltingFrequency != 0)
return;
for (var i = 0; i < Furnace.inventory.itemList.Count; i++)
{
// Getting item and checking if it's valid
var item = Furnace.inventory.itemList[i];
if (item == null || !item.IsValid())
continue;
// Getting cookable
var cookable = item.info.GetComponent<ItemModCookable>();
if (cookable == null)
continue;
// Checking if item's cooking is allowed
var isAllowed = IsAllowed(item.info.shortname);
if (isAllowed != null && !isAllowed.Value) // Allowed is false? Okay, no problem. Don't cook this item
continue;
// What about temperature?
// This lets us deny cooking, for example, meat in furnaces
var temperature = item.temperature;
if ((temperature < cookable.lowTemp || temperature > cookable.highTemp) && isAllowed == null) // Not allowed, not denied? That's our case! Because if it's allowed, this function won't be executed :P
{
if (!cookable.setCookingFlag || !item.HasFlag(global::Item.Flag.Cooking)) continue;
item.SetFlag(global::Item.Flag.Cooking, false);
item.MarkDirty();
continue;
}
// So, so.. what about items' cooking speed (time)?
if (cookable.cookTime > 0 && _ticks * 1f / _smeltingFrequency % cookable.cookTime > 0)
continue;
// Setting cooking flag
if (cookable.setCookingFlag && !item.HasFlag(global::Item.Flag.Cooking))
{
item.SetFlag(global::Item.Flag.Cooking, true);
item.MarkDirty();
}
// Changing amount
var position = item.position;
if (item.amount > 1)
{
item.amount--;
item.MarkDirty();
}
else
{
item.Remove();
}
// What if nothing is produced?
if (cookable.becomeOnCooked == null) continue;
// Let's create an item!
var item2 = ItemManager.Create(cookable.becomeOnCooked,
(int) (cookable.amountOfBecome * OutputMultiplier(cookable.becomeOnCooked.shortname))); // It's an another one output multiplier, but not for fuel
// Some checks
if (item2 == null || item2.MoveToContainer(item.parent, position) ||
item2.MoveToContainer(item.parent))
continue;
// Dropping item and stopping cooking if oven is full
item2.Drop(item.parent.dropPosition, item.parent.dropVelocity);
if (!item.parent.entityOwner) continue;
StopCooking();
}
}
public void StartCooking()
{
if (FindBurnable() == null)
{
PrintDebug("No burnable.");
return;
}
StopCooking();
PrintDebug("Starting cooking..");
Furnace.inventory.temperature = Furnace.cookingTemperature;
Furnace.UpdateAttachmentTemperature();
PrintDebug($"Speed Multiplier: {_speedMultiplier}");
Furnace.InvokeRepeating(Cook, _speedMultiplier, _speedMultiplier);
Furnace.SetFlag(BaseEntity.Flags.On, true);
}
public void StopCooking()
{
PrintDebug("Stopping cooking..");
Furnace.CancelInvoke(Cook);
Furnace.StopCooking();
}
}
#endregion
}
}

1275
plugins/QuickSort.cs Normal file

File diff suppressed because it is too large Load Diff

3353
plugins/RemoverTool.cs Normal file

File diff suppressed because it is too large Load Diff

1933
plugins/SkinBox.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,537 @@
using System.Collections.Generic;
using System.Linq;
using System;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Stack Size Controller", "Canopy Sheep", "2.0.4", ResourceId = 2320)]
[Description("Allows you to set the max stack size of every item.")]
public class StackSizeController : RustPlugin
{
#region Data
private bool pluginLoaded = false;
Items items;
class Items
{
public Dictionary<string, int> itemlist = new Dictionary<string, int>();
}
private bool LoadData()
{
var itemsdatafile = Interface.Oxide.DataFileSystem.GetFile("StackSizeController");
try
{
items = itemsdatafile.ReadObject<Items>();
return true;
}
catch (Exception ex)
{
PrintWarning("Error: Data file is corrupt. Debug info: " + ex.Message);
return false;
}
}
private void UpdateItems()
{
var gameitemList = ItemManager.itemList;
List<string> itemCategories = new List<string>();
int stacksize;
foreach (var item in gameitemList)
{
if (!itemCategories.Contains(item.category.ToString()))
{
if (!(configData.Settings.CategoryDefaultStack.ContainsKey(item.category.ToString())))
{
configData.Settings.CategoryDefaultStack[item.category.ToString()] = configData.Settings.NewCategoryDefaultSetting;
Puts("Added item category: '" + item.category.ToString() + "' to the config.");
}
itemCategories.Add(item.category.ToString());
}
if (!(items.itemlist.ContainsKey(item.displayName.english)))
{
stacksize = DetermineStack(item);
items.itemlist.Add(item.displayName.english, stacksize);
}
}
List<string> KeysToRemove = new List<string>();
foreach (KeyValuePair<string ,int> category in configData.Settings.CategoryDefaultStack)
{
if (!itemCategories.Contains(category.Key)) { KeysToRemove.Add(category.Key); }
}
if (KeysToRemove.Count > 0)
{
Puts("Cleaning config categories...");
foreach (string Key in KeysToRemove)
{
configData.Settings.CategoryDefaultStack.Remove(Key);
}
}
SaveConfig();
KeysToRemove = new List<string>();
bool foundItem = false;
foreach (KeyValuePair<string, int> item in items.itemlist)
{
foreach (var itemingamelist in gameitemList)
{
if (itemingamelist.displayName.english == item.Key)
{
foundItem = true;
break;
}
}
if (!(foundItem)) { KeysToRemove.Add(item.Key); }
foundItem = false;
}
if (KeysToRemove.Count > 0)
{
Puts("Cleaning data file...");
foreach (string key in KeysToRemove)
{
items.itemlist.Remove(key);
}
}
SaveData();
LoadStackSizes();
}
private int DetermineStack(ItemDefinition item)
{
if (item.condition.enabled && item.condition.max > 0 && (!configData.Settings.StackHealthItems))
{
return 1;
}
else
{
if (configData.Settings.DefaultStack != 0 && (!configData.Settings.CategoryDefaultStack.ContainsKey(item.category.ToString())))
{
return configData.Settings.DefaultStack;
}
else if (configData.Settings.CategoryDefaultStack.ContainsKey(item.category.ToString()) && configData.Settings.CategoryDefaultStack[item.category.ToString()] != 0)
{
return configData.Settings.CategoryDefaultStack[item.category.ToString()];
}
else if (configData.Settings.DefaultStack != 0 && configData.Settings.CategoryDefaultStack[item.category.ToString()] == 0)
{
return configData.Settings.DefaultStack;
}
else
{
return item.stackable;
}
}
}
private void LoadStackSizes()
{
var gameitemList = ItemManager.itemList;
foreach (var item in gameitemList)
{
item.stackable = items.itemlist[item.displayName.english];
}
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject("StackSizeController", items);
}
#endregion
#region Config
ConfigData configData;
class ConfigData
{
public SettingsData Settings { get; set; }
}
class SettingsData
{
public int DefaultStack { get; set; }
public int NewCategoryDefaultSetting { get; set; }
public bool StackHealthItems { get; set; }
public Dictionary<string, int> CategoryDefaultStack { get; set; }
}
private void TryConfig()
{
try
{
configData = Config.ReadObject<ConfigData>();
}
catch (Exception ex)
{
PrintWarning("Corrupt config detected, debug: " + ex.Message);
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig()
{
Puts("Generating a new config file...");
Config.WriteObject(new ConfigData
{
Settings = new SettingsData
{
DefaultStack = 0,
NewCategoryDefaultSetting = 0,
StackHealthItems = true,
CategoryDefaultStack = new Dictionary<string, int>()
{
{ "Ammunition", 0 },
{ "Weapon", 0 },
},
},
}, true);
}
private void SaveConfig()
{
Config.WriteObject(configData);
}
#endregion
#region Hooks
private void OnServerInitialized()
{
TryConfig();
pluginLoaded = LoadData();
if (pluginLoaded)
{
if (!configData.Settings.StackHealthItems) { Unsubscribe(); }
UpdateItems();
}
else { Puts("Stack Sizes could not be changed due to a corrupt data file."); }
permission.RegisterPermission("stacksizecontroller.canChangeStackSize", this);
}
private bool hasPermission(BasePlayer player, string perm)
{
if (player.net.connection.authLevel > 1)
{
return true;
}
return permission.UserHasPermission(player.userID.ToString(), perm);
}
private object CanStackItem(Item item, Item targetItem)
{
if (item.info.shortname != targetItem.info.shortname) { return null; }
if (item.contents != targetItem.contents) { return false; }
FlameThrower flamethrower = item.GetHeldEntity() as FlameThrower;
if (flamethrower != null)
{
if (flamethrower.ammo != (targetItem.GetHeldEntity() as FlameThrower).ammo) { return false; }
}
return null;
}
private void Unsubscribe()
{
Unsubscribe(nameof(CanStackItem));
}
#endregion
#region Commands
[ChatCommand("stack")]
private void StackCommand(BasePlayer player, string command, string[] args)
{
if (!hasPermission(player, "stacksizecontroller.canChangeStackSize"))
{
SendReply(player, "You don't have permission to use this command.");
return;
}
if (!pluginLoaded)
{
SendReply(player, "StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
return;
}
if (args.Length < 2)
{
SendReply(player, "Syntax Error: Requires 2 arguments. Syntax Example: /stack ammo.rocket.hv 64 (Use shortname)");
return;
}
int stackAmount = 0;
List<ItemDefinition> gameitems = ItemManager.itemList.FindAll(x => x.shortname.Equals(args[0]));
if (gameitems.Count == 0)
{
SendReply(player, "Syntax Error: That is an incorrect item name. Please use a valid shortname.");
return;
}
string replymessage = "";
switch (args[1].ToLower())
{
case "default":
{
stackAmount = DetermineStack(gameitems[0]);
replymessage = "Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + " (Default value based on config).";
break;
}
default:
{
if (int.TryParse(args[1], out stackAmount) == false)
{
SendReply(player, "Syntax Error: Stack Amount is not a number. Syntax Example: /stack ammo.rocket.hv 64 (Use shortname)");
return;
}
replymessage = "Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + ".";
break;
}
}
if (gameitems[0].condition.enabled && gameitems[0].condition.max > 0)
{
if (!(configData.Settings.StackHealthItems))
{
SendReply(player, "Error: Stacking health items is disabled in the config.");
return;
}
}
items.itemlist[gameitems[0].displayName.english] = Convert.ToInt32(stackAmount);
gameitems[0].stackable = Convert.ToInt32(stackAmount);
SaveData();
SendReply(player, replymessage);
}
[ChatCommand("stackall")]
private void StackAllCommand(BasePlayer player, string command, string[] args)
{
if (!hasPermission(player, "stacksizecontroller.canChangeStackSize"))
{
SendReply(player, "You don't have permission to use this command.");
return;
}
if (!pluginLoaded)
{
SendReply(player, "StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
return;
}
if (args.Length < 1)
{
SendReply(player, "Syntax Error: Requires 1 argument. Syntax Example: /stackall 65000");
return;
}
int stackAmount = 0;
string replymessage = "";
var itemList = ItemManager.itemList;
foreach (var gameitem in itemList)
{
switch (args[0].ToLower())
{
case "default":
{
stackAmount = DetermineStack(gameitem);
replymessage = "The Stack Size of all stackable items has been set to their default values (specified in config).";
break;
}
default:
{
if (int.TryParse(args[0], out stackAmount) == false)
{
SendReply(player, "Syntax Error: Stack Amount is not a number. Syntax Example: /stackall 65000");
return;
}
replymessage = "The Stack Size of all stackable items has been set to " + stackAmount.ToString() + ".";
break;
}
}
if (gameitem.condition.enabled && gameitem.condition.max > 0 && !(configData.Settings.StackHealthItems)) { continue; }
if (gameitem.displayName.english.ToString() == "Salt Water" || gameitem.displayName.english.ToString() == "Water") { continue; }
items.itemlist[gameitem.displayName.english] = Convert.ToInt32(stackAmount);
gameitem.stackable = Convert.ToInt32(stackAmount);
}
SaveData();
SendReply(player, replymessage);
}
[ConsoleCommand("stack")]
private void StackConsoleCommand(ConsoleSystem.Arg arg)
{
if (arg.IsAdmin != true)
{
if ((arg.Connection.userid.ToString() != null) && !(permission.UserHasPermission(arg.Connection.userid.ToString(), "stacksizecontroller.canChangeStackSize")))
{
arg.ReplyWith("[StackSizeController] You don't have permission to use this command.");
return;
}
}
if (!pluginLoaded)
{
arg.ReplyWith("[StackSizeController] StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
return;
}
if (arg.Args != null)
{
if (arg.Args.Length < 2)
{
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 2 arguments. Syntax Example: stack ammo.rocket.hv 64 (Use shortname)");
return;
}
}
else
{
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 2 arguments. Syntax Example: stack ammo.rocket.hv 64 (Use shortname)");
return;
}
int stackAmount = 0;
List<ItemDefinition> gameitems = ItemManager.itemList.FindAll(x => x.shortname.Equals(arg.Args[0]));
if (gameitems.Count == 0)
{
arg.ReplyWith("[StackSizeController] Syntax Error: That is an incorrect item name. Please use a valid shortname.");
return;
}
string replymessage = "";
switch (arg.Args[1].ToLower())
{
case "default":
{
stackAmount = DetermineStack(gameitems[0]);
replymessage = "[StackSizeController] Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + " (Default value based on config).";
break;
}
default:
{
if (int.TryParse(arg.Args[1], out stackAmount) == false)
{
arg.ReplyWith("[StackSizeController] Syntax Error: Stack Amount is not a number. Syntax Example: /stack ammo.rocket.hv 64 (Use shortname)");
return;
}
replymessage = "[StackSizeController] Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + ".";
break;
}
}
if (gameitems[0].condition.enabled && gameitems[0].condition.max > 0)
{
if (!(configData.Settings.StackHealthItems))
{
arg.ReplyWith("[StackSizeController] Error: Stacking health items is disabled in the config.");
return;
}
}
items.itemlist[gameitems[0].displayName.english] = Convert.ToInt32(stackAmount);
gameitems[0].stackable = Convert.ToInt32(stackAmount);
SaveData();
arg.ReplyWith(replymessage);
}
[ConsoleCommand("stackall")]
private void StackAllConsoleCommand(ConsoleSystem.Arg arg)
{
if (arg.IsAdmin != true)
{
if ((arg.Connection.userid.ToString() != null) && !(permission.UserHasPermission(arg.Connection.userid.ToString(), "stacksizecontroller.canChangeStackSize")))
{
arg.ReplyWith("[StackSizeController] You don't have permission to use this command.");
return;
}
}
if (!pluginLoaded)
{
arg.ReplyWith("[StackSizeController] StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
return;
}
if (arg.Args != null)
{
if (arg.Args.Length < 1)
{
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 1 argument. Syntax Example: stackall 65000");
return;
}
}
else
{
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 1 argument. Syntax Example: stackall 65000");
return;
}
int stackAmount = 0;
string replymessage = "";
var itemList = ItemManager.itemList;
foreach (var gameitem in itemList)
{
if (gameitem.condition.enabled && gameitem.condition.max > 0 && (!(configData.Settings.StackHealthItems))) { continue; }
if (gameitem.displayName.english.ToString() == "Salt Water" ||
gameitem.displayName.english.ToString() == "Water") { continue; }
switch (arg.Args[0].ToLower())
{
case "default":
{
stackAmount = DetermineStack(gameitem);
replymessage = "[StackSizeController] The Stack Size of all stackable items has been set to their default values (specified in config).";
break;
}
default:
{
if (int.TryParse(arg.Args[0], out stackAmount) == false)
{
arg.ReplyWith("[StackSizeController] Syntax Error: Stack Amount is not a number. Syntax Example: /stackall 65000");
return;
}
replymessage = "[StackSizeController] The Stack Size of all stackable items has been set to " + stackAmount.ToString() + ".";
break;
}
}
items.itemlist[gameitem.displayName.english] = Convert.ToInt32(stackAmount);
gameitem.stackable = Convert.ToInt32(stackAmount);
}
SaveData();
arg.ReplyWith(replymessage);
}
#endregion
}
}

355
plugins/TimeOfDay.cs Normal file
View File

@ -0,0 +1,355 @@
using Oxide.Core.Plugins;
using Oxide.Core;
using System;
using System.Text;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("TimeOfDay", "FuJiCuRa", "2.3.4")]
[Description("Does alter day and night duration.")]
public class TimeOfDay : RustPlugin
{
bool Changed;
bool Initialized;
int componentSearchAttempts;
TOD_Time timeComponent;
bool activatedDay;
int authLevelCmds;
int authLevelFreeze;
int dayLength;
int nightLength;
int presetDay;
int presetMonth;
int presetYear;
bool setPresetDate;
bool freezeDate;
bool autoSkipNight;
bool autoSkipDay;
bool logAutoSkipConsole;
bool freezeTimeOnload;
float timeToFreeze;
object GetConfig(string menu, string datavalue, object defaultValue)
{
var data = Config[menu] as Dictionary<string, object>;
if (data == null)
{
data = new Dictionary<string, object>();
Config[menu] = data;
Changed = true;
}
object value;
if (!data.TryGetValue(datavalue, out value))
{
value = defaultValue;
data[datavalue] = value;
Changed = true;
}
return value;
}
void LoadVariables()
{
dayLength = System.Convert.ToInt32(GetConfig("Settings", "dayLength", 30));
nightLength = System.Convert.ToInt32(GetConfig("Settings", "nightLength", 30));
freezeDate = System.Convert.ToBoolean(GetConfig("Settings", "freezeDate", false));
authLevelCmds = System.Convert.ToInt32(GetConfig("Settings", "authLevelCmds", 1));
authLevelFreeze = System.Convert.ToInt32(GetConfig("Settings", "authLevelFreeze", 2));
autoSkipNight = System.Convert.ToBoolean(GetConfig("Settings", "autoSkipNight", false));
autoSkipDay = System.Convert.ToBoolean(GetConfig("Settings", "autoSkipDay", false));
logAutoSkipConsole = System.Convert.ToBoolean(GetConfig("Settings", "logAutoSkipConsole", true));
presetDay = System.Convert.ToInt32(GetConfig("DatePreset", "presetDay", 1));
presetMonth = System.Convert.ToInt32(GetConfig("DatePreset", "presetMonth", 1));
presetYear = System.Convert.ToInt32(GetConfig("DatePreset", "presetYear", 2020));
setPresetDate = System.Convert.ToBoolean(GetConfig("DatePreset", "setPresetDate", false));
freezeTimeOnload = System.Convert.ToBoolean(GetConfig("TimeFreeze", "freezeTimeOnload", false));
timeToFreeze = System.Convert.ToSingle(GetConfig("TimeFreeze", "timeToFreeze", 12.0));
if (!Changed) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig()
{
Config.Clear();
LoadVariables();
}
void Loaded()
{
LoadVariables();
Initialized = false;
}
void Unload()
{
if (timeComponent == null || !Initialized) return;
timeComponent.OnSunrise -= OnSunrise;
timeComponent.OnSunset -= OnSunset;
timeComponent.OnDay -= OnDay;
timeComponent.OnHour -= OnHour;
}
void OnServerInitialized()
{
if (TOD_Sky.Instance == null)
{
componentSearchAttempts++;
if (componentSearchAttempts < 10)
timer.Once(1, OnServerInitialized);
else
PrintWarning("Could not find required component after 10 attempts. Plugin disabled");
return;
}
timeComponent = TOD_Sky.Instance.Components.Time;
if (timeComponent == null)
{
PrintWarning("Could not fetch time component. Plugin disabled");
return;
}
if (setPresetDate)
{
TOD_Sky.Instance.Cycle.Day = presetDay;
TOD_Sky.Instance.Cycle.Month = presetMonth;
TOD_Sky.Instance.Cycle.Year = presetYear;
}
SetTimeComponent();
if (freezeTimeOnload)
StartupFreeze();
}
void SetTimeComponent()
{
timeComponent.ProgressTime = true;
timeComponent.UseTimeCurve = false;
timeComponent.OnSunrise += OnSunrise;
timeComponent.OnSunset += OnSunset;
timeComponent.OnDay += OnDay;
timeComponent.OnHour += OnHour;
Initialized = true;
if (TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunriseTime && TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunsetTime)
OnSunrise();
else
OnSunset();
}
void StartupFreeze()
{
if (!Initialized) return;
timeComponent.ProgressTime = false;
ConVar.Env.time = timeToFreeze;
}
void OnDay()
{
if (Initialized && freezeDate)
--TOD_Sky.Instance.Cycle.Day;
}
void OnHour()
{
if (!Initialized) return;
if (TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunriseTime && TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunsetTime && !activatedDay)
{
OnSunrise();
return;
}
if ((TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunsetTime || TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunriseTime) && activatedDay)
{
OnSunset();
return;
}
}
void OnSunrise()
{
if (!Initialized) return;
if (autoSkipDay && !autoSkipNight)
{
TOD_Sky.Instance.Cycle.Hour = TOD_Sky.Instance.SunsetTime;
if (logAutoSkipConsole)
Puts("Daytime autoskipped");
OnSunset();
return;
}
timeComponent.DayLengthInMinutes = dayLength * (24.0f / (TOD_Sky.Instance.SunsetTime - TOD_Sky.Instance.SunriseTime));
if (!activatedDay)
Interface.CallHook("OnTimeSunrise");
activatedDay = true;
}
void OnSunset()
{
if (!Initialized) return;
if (autoSkipNight)
{
float timeToAdd = (24 - TOD_Sky.Instance.Cycle.Hour) + TOD_Sky.Instance.SunriseTime;
TOD_Sky.Instance.Cycle.Hour += timeToAdd;
if (logAutoSkipConsole)
Puts("Nighttime autoskipped");
OnSunrise();
return;
}
timeComponent.DayLengthInMinutes = nightLength * (24.0f / (24.0f - (TOD_Sky.Instance.SunsetTime - TOD_Sky.Instance.SunriseTime)));
if (activatedDay)
Interface.CallHook("OnTimeSunset");
activatedDay = false;
}
[ConsoleCommand("tod.daylength")]
void ConsoleDayLength(ConsoleSystem.Arg arg)
{
if (!Initialized) return;
if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return;
if (arg.Args == null || arg.Args.Length < 1)
{
SendReply(arg, $"Current 'dayLength' setting is '{dayLength}'");
return;
}
int newDaylength = 0;
if (int.TryParse(arg.Args[0], out newDaylength))
{
if (newDaylength < 1)
{
SendReply(arg, $"The new daylength must be greater zero");
return;
}
}
dayLength = newDaylength;
SendReply(arg, $"The 'dayLength' has been set to '{dayLength}'");
if (TOD_Sky.Instance.IsDay)
OnSunrise();
else
OnSunset();
Config["Settings", "dayLength"] = dayLength;
SaveConfig();
}
[ConsoleCommand("tod.nightlength")]
void ConsoleNightLength(ConsoleSystem.Arg arg)
{
if (!Initialized) return;
if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return;
if (arg.Args == null || arg.Args.Length < 1)
{
SendReply(arg, $"Current 'nightLength' setting is '{nightLength}'");
return;
}
int newNightlength = 0;
if (int.TryParse(arg.Args[0], out newNightlength))
{
if (newNightlength < 1)
{
SendReply(arg, $"The new nightlength must be greater zero");
return;
}
}
nightLength = newNightlength;
SendReply(arg, $"The 'nightLength' has been set to '{nightLength}'");
if (TOD_Sky.Instance.IsDay)
OnSunrise();
else
OnSunset();
Config["Settings", "nightLength"] = nightLength;
SaveConfig();
}
[ConsoleCommand("tod.freezetime")]
void ConsoleFreezeTime(ConsoleSystem.Arg arg)
{
if (!Initialized) return;
if (arg.Connection != null && arg.Connection.authLevel < authLevelFreeze) return;
timeComponent.ProgressTime = !timeComponent.ProgressTime;
if (timeComponent.ProgressTime)
SendReply(arg, $"The game time was unfreezed");
else
SendReply(arg, $"The game time was freezed");
}
[ConsoleCommand("tod.skipday")]
void ConsoleSkipDay(ConsoleSystem.Arg arg)
{
if (!Initialized) return;
if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return;
if (TOD_Sky.Instance.IsNight)
{
SendReply(arg, $"Night is already active");
return;
}
OnSunset();
TOD_Sky.Instance.Cycle.Hour = TOD_Sky.Instance.SunsetTime;
SendReply(arg, $"Current daytime skipped");
}
[ConsoleCommand("tod.skipnight")]
void ConsoleSkipNight(ConsoleSystem.Arg arg)
{
if (!Initialized) return;
if (arg.Connection != null && arg.Connection.authLevel < authLevelCmds) return;
if (TOD_Sky.Instance.IsDay)
{
SendReply(arg, $"Day is already active");
return;
}
OnSunrise();
TOD_Sky.Instance.Cycle.Hour = TOD_Sky.Instance.SunriseTime;
SendReply(arg, $"Current nighttime skipped");
}
[ChatCommand("tod")]
private void TodCommand(BasePlayer player, string command, string[] args)
{
if (!Initialized)
return;
TimeSpan ts1= TimeSpan.FromHours(TOD_Sky.Instance.SunriseTime);
TimeSpan ts2= TimeSpan.FromHours(TOD_Sky.Instance.SunsetTime);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine(FormNeutralMessage("-------- Settings --------"));
stringBuilder.AppendLine("Current Time".PadRight(15) + TOD_Sky.Instance.Cycle.DateTime.ToString("HH:mm:ss"));
stringBuilder.AppendLine("Sunrise Hour".PadRight(15) + string.Format("{0}:{1}", System.Math.Truncate(ts1.TotalHours).ToString(), ts1.Minutes.ToString()));
stringBuilder.AppendLine("Sunset Hour".PadRight(15) + string.Format("{0}:{1}", System.Math.Truncate(ts2.TotalHours).ToString(), ts2.Minutes.ToString()));
stringBuilder.AppendLine("Daylength".PadRight(15) + dayLength.ToString() + " minutes");
stringBuilder.Append("Nightlength".PadRight(15) + nightLength.ToString() + " minutes");
PrintPluginMessageToChat(player, stringBuilder.ToString().TrimEnd());
}
[HookMethod("SendHelpText")]
private void SendHelpText(BasePlayer player)
{
if (!Initialized) return;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(FormNeutralMessage("-------------------- Available Commands --------------------\n"));
stringBuilder.Append(FormNeutralMessage("/tod") + " - Shows current Time Of Day.\n");
PrintPluginMessageToChat(player, stringBuilder.ToString());
}
private void PrintPluginMessageToChat(BasePlayer player, string message)
{
PrintToChat(player, "<b><size=16>[<color=#ffa500ff>" + this.Name + "</color>]</size></b>\n" + message);
}
private void PrintPluginMessageToChat(string message)
{
PrintToChat("<b><size=16>[<color=#ffa500ff>" + this.Name + "</color>]</size></b>\n" + message);
}
private string FormNeutralMessage(string message)
{
return "<color=#c0c0c0ff>" + message + "</color>";
}
}
}

71
plugins/UnburnableMeat.cs Normal file
View File

@ -0,0 +1,71 @@
using System.Collections.Generic;
namespace Oxide.Plugins
{
[Info("Unburnable Meat", "S642667", "1.0.1")]
[Description("Prevent cooked meats from burning")]
class UnburnableMeat : RustPlugin
{
public static readonly string[] CookedItems = new string[]
{
"bearmeat.cooked",
"chicken.cooked",
"deermeat.cooked",
"horsemeat.cooked",
"humanmeat.cooked",
"meat.pork.cooked",
"wolfmeat.cooked",
"fish.cooked"
};
private Dictionary<string, int> lowTemps = new Dictionary<string, int>();
private Dictionary<string, int> highTemps = new Dictionary<string, int>();
ItemModCookable GetCookable (string shortname)
{
var definition = ItemManager.FindItemDefinition(shortname);
if (definition == null)
{
Puts($"Unknown definition for {shortname}");
return null;
}
var cookable = definition.GetComponent<ItemModCookable>();
if (cookable == null)
{
Puts($"Unknown cookable for {shortname}");
return null;
}
return cookable;
}
void OnServerInitialized()
{
foreach (var shortname in CookedItems)
{
var cookable = GetCookable(shortname);
if (cookable == null)
{
continue;
}
lowTemps.Add(shortname, cookable.lowTemp);
highTemps.Add(shortname, cookable.highTemp);
cookable.lowTemp = -1;
cookable.highTemp = -1;
}
}
void Unload()
{
foreach (KeyValuePair<string, int> item in lowTemps)
{
var cookable = GetCookable(item.Key);
if (cookable == null)
{
continue;
}
cookable.lowTemp = item.Value;
cookable.highTemp = highTemps[item.Key];
}
}
}
}

428
plugins/Vanish.cs Normal file
View File

@ -0,0 +1,428 @@
using Network;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using Rust;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Vanish", "Whispers88", "1.3.8")]
[Description("Allows players with permission to become invisible")]
public class Vanish : RustPlugin
{
#region Configuration
private readonly List<BasePlayer> _hiddenPlayers = new List<BasePlayer>();
private readonly List<BasePlayer> _hiddenOffline = new List<BasePlayer>();
private static List<string> _registeredhooks = new List<string> { "OnNpcTarget", "CanBeTargeted", "CanHelicopterTarget", "CanHelicopterStrafeTarget", "CanBradleyApcTarget", "CanUseLockedEntity", "OnEntityTakeDamage", "OnPlayerDisconnected" };
private static readonly DamageTypeList _EmptyDmgList = new DamageTypeList();
CuiElementContainer cachedVanishUI = null;
private Configuration config;
public class Configuration
{
[JsonProperty("NoClip on Vanish (runs noclip command)")]
public bool NoClipOnVanish = true;
[JsonProperty("Hide an invisible players body under the terrain after disconnect")]
public bool HideOnDisconnect = false;
[JsonProperty("If a player was vanished on disconnection keep them vanished on reconnect")]
public bool HideOnReconnect = true;
[JsonProperty("Turn off fly hack detection for players in vanish")]
public bool AntiFlyHack = true;
[JsonProperty("Enable vanishing and reappearing sound effects")]
public bool EnableSound = true;
[JsonProperty("Make sound effects public")]
public bool PublicSound = false;
[JsonProperty("Enable chat notifications")]
public bool EnableNotifications = true;
[JsonProperty("Sound effect to use when vanishing")]
public string VanishSoundEffect = "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab";
[JsonProperty("Sound effect to use when reappearing")]
public string ReappearSoundEffect = "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab";
[JsonProperty("Enable GUI")]
public bool EnableGUI = true;
[JsonProperty("Icon URL (.png or .jpg)")]
public string ImageUrlIcon = "http://i.imgur.com/Gr5G3YI.png";
[JsonProperty("Image Color")]
public string ImageColor = "1 1 1 0.3";
[JsonProperty("Image AnchorMin")]
public string ImageAnchorMin = "0.175 0.017";
[JsonProperty("Image AnchorMax")]
public string ImageAnchorMax = "0.22 0.08";
public string ToJson() => JsonConvert.SerializeObject(this);
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null)
{
throw new JsonException();
}
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
{
PrintToConsole("Configuration appears to be outdated; updating and saving");
SaveConfig();
}
}
catch
{
PrintToConsole($"Configuration file {Name}.json is invalid; using defaults");
LoadDefaultConfig();
}
}
protected override void SaveConfig()
{
PrintToConsole($"Configuration changes saved to {Name}.json");
Config.WriteObject(config, true);
}
#endregion Configuration
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["VanishCommand"] = "vanish",
["CollisionToggle"] = "collider",
["Vanished"] = "Vanish: <color=orange> Enabled </color>",
["Reappear"] = "Vanish: <color=orange> Disabled </color>",
["NoPerms"] = "You do not have permission to do this",
["PermanentVanish"] = "You are in a permanent vanish mode",
["ColliderEnbabled"] = "Player Collider: <color=orange> Enabled </color>",
["ColliderDisabled"] = "Player Collider: <color=orange> Disabled </color>"
}, this);
}
#endregion Localization
#region Initialization
private const string permallow = "vanish.allow";
private const string permunlock = "vanish.unlock";
private const string permdamage = "vanish.damage";
private const string permavanish = "vanish.permanent";
private const string permcollision = "vanish.collision";
private void Init()
{
cachedVanishUI = CreateVanishUI();
// Register univeral chat/console commands
AddLocalizedCommand(nameof(VanishCommand));
AddLocalizedCommand(nameof(CollisionToggle));
// Register permissions for commands
permission.RegisterPermission(permallow, this);
permission.RegisterPermission(permunlock, this);
permission.RegisterPermission(permdamage, this);
permission.RegisterPermission(permavanish, this);
permission.RegisterPermission(permcollision, this);
//Unsubscribe from hooks
UnSubscribeFromHooks();
BasePlayer.activePlayerList.Where(i => HasPerm(i.UserIDString, permavanish) && !IsInvisible(i)).ToList().ForEach(j => Disappear(j));
}
private void Unload()
{
_hiddenPlayers.Where(i => i != null).ToList().ForEach(j => Reappear(j));
}
#endregion Initialization
#region Commands
private void VanishCommand(IPlayer iplayer, string command, string[] args)
{
var player = (BasePlayer)iplayer.Object;
if (!HasPerm(player.UserIDString, permallow))
{
if (config.EnableNotifications) Message(player.IPlayer, "NoPerms");
return;
}
if (HasPerm(player.UserIDString, permavanish))
{
if (config.EnableNotifications) Message(player.IPlayer, "PermanentVanish");
return;
}
if (IsInvisible(player)) Reappear(player);
else Disappear(player);
}
private void CollisionToggle(IPlayer iplayer, string command, string[] args)
{
var player = (BasePlayer)iplayer.Object;
if (!IsInvisible(player)) return;
if (!HasPerm(player.UserIDString, permcollision))
{
if (config.EnableNotifications) Message(player.IPlayer, "NoPerms");
return;
}
var col = player.gameObject.GetComponent<Collider>();
if (!col.enabled)
{
player.EnablePlayerCollider();
Message(player.IPlayer, "ColliderEnbabled");
return;
}
player.DisablePlayerCollider();
Message(player.IPlayer, "ColliderDisabled");
}
private void Reappear(BasePlayer player)
{
if (Interface.CallHook("OnVanishReappear", player) != null) return;
if (config.AntiFlyHack) player.ResetAntiHack();
player._limitedNetworking = false;
player.EnablePlayerCollider();
player.SendNetworkUpdate();
player.GetHeldEntity()?.SendNetworkUpdate();
player.drownEffect.guid = "28ad47c8e6d313742a7a2740674a25b5";
player.fallDamageEffect.guid = "ca14ed027d5924003b1c5d9e523a5fce";
_hiddenPlayers.Remove(player);
if (_hiddenPlayers.Count == 0) UnSubscribeFromHooks();
if (config.EnableSound)
{
if (config.PublicSound)
{
Effect.server.Run(config.ReappearSoundEffect, player.transform.position);
}
else
{
SendEffect(player, config.ReappearSoundEffect);
}
}
CuiHelper.DestroyUi(player, "VanishUI");
if (config.NoClipOnVanish && player.IsFlying) player.SendConsoleCommand("noclip");
if (config.EnableNotifications) Message(player.IPlayer, "Reappear");
}
private void Disappear(BasePlayer player)
{
if (Interface.CallHook("OnVanishDisappear", player) != null) return;
if (config.AntiFlyHack) player.PauseFlyHackDetection();
//Mute Player Effects
player.fallDamageEffect = new GameObjectRef();
player.drownEffect = new GameObjectRef();
AntiHack.ShouldIgnore(player);
if (_hiddenPlayers.Count == 0) SubscribeToHooks();
player._limitedNetworking = true;
player.DisablePlayerCollider();
var connections = Net.sv.connections.Where(con => con.connected && con.isAuthenticated && con.player is BasePlayer && con.player != player).ToList();
player.OnNetworkSubscribersLeave(connections);
_hiddenPlayers.Add(player);
if (config.EnableSound)
{
if (config.PublicSound)
{
Effect.server.Run(config.VanishSoundEffect, player.transform.position);
}
else
{
SendEffect(player, config.VanishSoundEffect);
}
}
if (config.NoClipOnVanish && !player.IsFlying && !player.isMounted) player.SendConsoleCommand("noclip");
if (config.EnableGUI) CuiHelper.AddUi(player, cachedVanishUI);
if (config.EnableNotifications) Message(player.IPlayer, "Vanished");
}
#endregion Commands
#region Hooks
private void OnPlayerConnected(BasePlayer player)
{
if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot))
{
timer.In(3, () => OnPlayerConnected(player));
return;
}
if (_hiddenOffline.Contains(player))
{
_hiddenOffline.Remove(player);
if (HasPerm(player.UserIDString, permallow))
Disappear(player);
}
if (HasPerm(player.UserIDString, permavanish))
{
Disappear(player);
}
}
private object OnNpcTarget(BaseEntity entity, BasePlayer target) => IsInvisible(target) ? (object)true : null;
private object CanBeTargeted(BasePlayer player, MonoBehaviour behaviour) => IsInvisible(player) ? (object)false : null;
private object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player) => IsInvisible(player) ? (object)false : null;
private object CanHelicopterStrafeTarget(PatrolHelicopterAI heli, BasePlayer player) => IsInvisible(player) ? (object)false : null;
private object CanBradleyApcTarget(BradleyAPC apc, BasePlayer player) => IsInvisible(player) ? (object)false : null;
private object CanUseLockedEntity(BasePlayer player, BaseLock baseLock)
{
if (IsInvisible(player))
{
if (HasPerm(player.UserIDString, permunlock)) return true;
if (config.EnableNotifications) Message(player.IPlayer, "NoPerms");
}
return null;
}
private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
var attacker = info?.InitiatorPlayer;
var victim = entity?.ToPlayer();
if (!IsInvisible(victim) && !IsInvisible(attacker)) return null;
if (IsInvisible(attacker) && HasPerm(attacker.UserIDString, permdamage)) return null;
if (info != null)
{
info.damageTypes = _EmptyDmgList;
info.HitMaterial = 0;
info.PointStart = Vector3.zero;
info.HitEntity = null;
}
return true;
}
private void OnPlayerDisconnected(BasePlayer player, string reason)
{
if (!IsInvisible(player)) return;
player._limitedNetworking = false;
player.EnablePlayerCollider();
player.SendNetworkUpdate();
player.GetHeldEntity()?.SendNetworkUpdate();
_hiddenPlayers.Remove(player);
if (_hiddenPlayers.Count == 0) UnSubscribeFromHooks();
if (config.HideOnDisconnect)
{
var pos = player.transform.position;
var underTerrainPos = new Vector3(pos.x, TerrainMeta.HeightMap.GetHeight(pos) - 5, pos.z);
player.Teleport(underTerrainPos);
player.DisablePlayerCollider();
}
if (config.HideOnReconnect)
_hiddenOffline.Add(player);
CuiHelper.DestroyUi(player, "VanishUI");
}
#endregion Hooks
#region GUI
private CuiElementContainer CreateVanishUI()
{
CuiElementContainer elements = new CuiElementContainer();
string panel = elements.Add(new CuiPanel
{
Image = { Color = "0.5 0.5 0.5 0.0" },
RectTransform = { AnchorMin = config.ImageAnchorMin, AnchorMax = config.ImageAnchorMax }
}, "Hud.Menu", "VanishUI");
elements.Add(new CuiElement
{
Parent = panel,
Components =
{
new CuiRawImageComponent {Color = config.ImageColor, Url = config.ImageUrlIcon},
new CuiRectTransformComponent {AnchorMin = "0 0", AnchorMax = "1 1"}
}
});
return elements;
}
#endregion GUI
#region Helpers
private void AddLocalizedCommand(string command)
{
foreach (string language in lang.GetLanguages(this))
{
Dictionary<string, string> messages = lang.GetMessages(language, this);
foreach (KeyValuePair<string, string> message in messages)
{
if (!message.Key.Equals(command)) continue;
if (string.IsNullOrEmpty(message.Value)) continue;
AddCovalenceCommand(message.Value, command);
}
}
}
private bool HasPerm(string id, string perm) => permission.UserHasPermission(id, perm);
private string GetLang(string langKey, string playerId = null, params object[] args)
{
return string.Format(lang.GetMessage(langKey, this, playerId), args);
}
private void Message(IPlayer player, string langKey, params object[] args)
{
if (player.IsConnected) player.Message(GetLang(langKey, player.Id, args));
}
private bool IsInvisible(BasePlayer player) => player != null && _hiddenPlayers.Contains(player);
private void UnSubscribeFromHooks()
{
foreach (var hook in _registeredhooks)
Unsubscribe(hook);
}
private void SubscribeToHooks()
{
foreach (var hook in _registeredhooks)
Subscribe(hook);
}
private void SendEffect(BasePlayer player, string sound)
{
var effect = new Effect(sound, player, 0, Vector3.zero, Vector3.forward);
EffectNetwork.Send(effect, player.net.connection);
}
#endregion Helpers
#region Public Helpers
public void _Disappear(BasePlayer basePlayer) => Disappear(basePlayer);
public void _Reappear(BasePlayer basePlayer) => Reappear(basePlayer);
public bool _IsInvisible(BasePlayer basePlayer) => IsInvisible(basePlayer);
#endregion
}
}

198
plugins/WipeKits.cs Normal file
View File

@ -0,0 +1,198 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Wipe Kits", "Ryan", "1.2.51")]
[Description("Puts a configurable cooldown on each kit depending on their kitname.")]
public class WipeKits : RustPlugin
{
#region Declaration
private static ConfigFile _cFile;
private DateTime _cachedWipeTime;
private const string Perm = "wipekits.bypass";
#endregion
#region Config
private class ConfigFile
{
[JsonProperty(PropertyName = "Kit Names & Cooldowns - Cooldowns (minutes)")]
public Dictionary<string, float> Kits;
[JsonProperty(PropertyName = "Use GUI Kits (true/false)")]
public bool UseGui { get; set; }
public static ConfigFile DefaultConfig()
{
return new ConfigFile
{
Kits = new Dictionary<string, float>()
{
["kitname1"] = 5,
["kitname2"] = 5
},
UseGui = false
};
}
}
protected override void LoadDefaultConfig()
{
PrintWarning("Loading default configuration file...");
_cFile = ConfigFile.DefaultConfig();
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_cFile = Config.ReadObject<ConfigFile>();
if (_cFile == null)
{
Regenerate();
}
}
catch { Regenerate(); }
}
protected override void SaveConfig() => Config.WriteObject(_cFile);
private void Regenerate()
{
PrintWarning($"Configuration file at 'oxide/config/{Name}.json' seems to be corrupt, regenerating...");
LoadDefaultConfig();
}
#endregion Config
#region Lang
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
// Time formatting
["DayFormat"] = "<color=orange>{0}</color> day and <color=orange>{1}</color> hours",
["DaysFormat"] = "<color=orange>{0}</color> days and <color=orange>{1}</color> hours",
["HourFormat"] = "<color=orange>{0}</color> hour and <color=orange>{1}</color> minutes",
["HoursFormat"] = "<color=orange>{0}</color> hours and <color=orange>{1}</color> minutes",
["MinFormat"] = "<color=orange>{0}</color> minute and <color=orange>{1}</color> seconds",
["MinsFormat"] = "<color=orange>{0}</color> minutes and <color=orange>{1}</color> seconds",
["SecsFormat"] = "<color=orange>{0}</color> seconds",
// Can't use command
["CantUse"] = "The server's just wiped! Try again in {0}",
}, this);
}
#endregion Lang
#region Methods
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private string GetFormattedTime(double time)
{
var timeSpan = TimeSpan.FromSeconds(time);
if (timeSpan.TotalSeconds < 1)
{
return null;
}
if (Math.Floor(timeSpan.TotalDays) >= 1)
{
return string.Format(timeSpan.Days > 1 ? Lang("DaysFormat", null, timeSpan.Days, timeSpan.Hours) : Lang("DayFormat", null, timeSpan.Days, timeSpan.Hours));
}
if (Math.Floor(timeSpan.TotalMinutes) >= 60)
{
return string.Format(timeSpan.Hours > 1 ? Lang("HoursFormat", null, timeSpan.Hours, timeSpan.Minutes) : Lang("HourFormat", null, timeSpan.Hours, timeSpan.Minutes));
}
if (Math.Floor(timeSpan.TotalSeconds) >= 60)
{
return string.Format(timeSpan.Minutes > 1 ? Lang("MinsFormat", null, timeSpan.Minutes, timeSpan.Seconds) : Lang("MinFormat", null, timeSpan.Minutes, timeSpan.Seconds));
}
return Lang("SecsFormat", null, timeSpan.Seconds);
}
private TimeSpan GetNextKitTime(float cooldown)
{
var timeSince = TimeSpan.FromSeconds((DateTime.UtcNow.ToLocalTime() - _cachedWipeTime).TotalSeconds);
if (timeSince.TotalSeconds > cooldown * 60)
{
return TimeSpan.Zero;
}
double timeUntil = cooldown * 60 - Math.Round(timeSince.TotalSeconds);
return TimeSpan.FromSeconds(timeUntil);
}
#endregion
#region Hooks
private void OnServerInitialized()
{
if(!_cFile.UseGui)
{
Unsubscribe(nameof(OnServerCommand));
}
_cachedWipeTime = SaveRestore.SaveCreatedTime.ToLocalTime();
}
private object OnServerCommand(ConsoleSystem.Arg arg)
{
var player = arg?.Player();
if (player == null || arg.cmd == null)
{
return null;
}
if (arg.cmd.FullName.ToLower().StartsWith("kit.gui") && _cFile.Kits.ContainsKey(arg.GetString(0).ToLower()))
{
float kitCooldown = _cFile.Kits[arg.GetString(0).ToLower()];
if (GetNextKitTime(kitCooldown) != TimeSpan.Zero)
{
player.SendConsoleCommand("kit.close");
PrintToChat(player, Lang("CantUse", player.UserIDString, GetFormattedTime(GetNextKitTime(kitCooldown).TotalSeconds)));
return true;
}
}
return null;
}
private object OnPlayerCommand(BasePlayer player, string command, string[] args)
{
if (command.ToLower() == "kit")
{
float kitCooldown;
if (!args.Any() || !_cFile.Kits.TryGetValue(args[0].Replace("\"", ""), out kitCooldown))
{
return null;
}
if (GetNextKitTime(kitCooldown) == TimeSpan.Zero)
{
return null;
}
PrintToChat(player, Lang("CantUse", player.UserIDString, GetFormattedTime(GetNextKitTime(kitCooldown).TotalSeconds)));
return true;
}
return null;
}
#endregion
}
}