SickGaming Rust Server Plugins
This commit is contained in:
commit
b76e392940
57
config/BetterLoot.json
Normal file
57
config/BetterLoot.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
3383
config/CraftingController.json
Normal file
3383
config/CraftingController.json
Normal file
File diff suppressed because it is too large
Load Diff
51
config/GatherManager.json
Normal file
51
config/GatherManager.json
Normal 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
44
config/Kits.json
Normal 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
|
||||
}
|
||||
}
|
||||
11
config/PermissionsManager.json
Normal file
11
config/PermissionsManager.json
Normal 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
44
config/QuickSmelt.json
Normal 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
22
config/TimeOfDay.json
Normal 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
7
config/WipeKits.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"Kit Names & Cooldowns - Cooldowns (minutes)": {
|
||||
"kitname1": 5.0,
|
||||
"kitname2": 5.0
|
||||
},
|
||||
"Use GUI Kits (true/false)": false
|
||||
}
|
||||
5
data/BetterLoot/Blacklist.json
Normal file
5
data/BetterLoot/Blacklist.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"ItemList": [
|
||||
"flare"
|
||||
]
|
||||
}
|
||||
4739
data/BetterLoot/LootTables.json
Normal file
4739
data/BetterLoot/LootTables.json
Normal file
File diff suppressed because it is too large
Load Diff
685
data/BetterLoot/NamesList.json
Normal file
685
data/BetterLoot/NamesList.json
Normal 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
3
data/Kits.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"Kits": {}
|
||||
}
|
||||
1
data/Kits_Data.json
Normal file
1
data/Kits_Data.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
||||
6
data/oxide.covalence.data
Normal file
6
data/oxide.covalence.data
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
-
|
||||
76561198106966240ŕńůĹ<C5AF>€€<E282AC>Sick Prodigy
|
||||
+
|
||||
76561198017312452Äí™›<E284A2>€€<E282AC>
|
||||
Dunkeykong
|
||||
BIN
data/oxide.groups.data
Normal file
BIN
data/oxide.groups.data
Normal file
Binary file not shown.
4
data/oxide.lang.data
Normal file
4
data/oxide.lang.data
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
en
|
||||
76561198106966240en
|
||||
76561198017312452en
|
||||
8
data/oxide.users.data
Normal file
8
data/oxide.users.data
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
3
|
||||
76561198106966240
|
||||
default
|
||||
adminSick Prodigy
|
||||
'
|
||||
76561198017312452
|
||||
defaultUnnamed
|
||||
27
lang/en/CraftingController.json
Normal file
27
lang/en/CraftingController.json
Normal 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
33
lang/en/Kits.json
Normal 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"
|
||||
}
|
||||
24
lang/en/PermissionsManager.json
Normal file
24
lang/en/PermissionsManager.json
Normal 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
67
lang/en/RustCore.json
Normal 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
10
lang/en/WipeKits.json
Normal 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}"
|
||||
}
|
||||
12
logs/compiler_08-02-2021.txt
Normal file
12
logs/compiler_08-02-2021.txt
Normal 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
244
logs/oxide_2021-02-08.txt
Normal 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
23
oxide.config.json
Normal 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
1813
plugins/AdminLogger.cs
Normal file
File diff suppressed because it is too large
Load Diff
1688
plugins/AutomaticAuthorization.cs
Normal file
1688
plugins/AutomaticAuthorization.cs
Normal file
File diff suppressed because it is too large
Load Diff
1357
plugins/Backpacks.cs
Normal file
1357
plugins/Backpacks.cs
Normal file
File diff suppressed because it is too large
Load Diff
953
plugins/BetterChat.cs
Normal file
953
plugins/BetterChat.cs
Normal 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
880
plugins/BetterLoot.cs
Normal 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
705
plugins/BlueprintShare.cs
Normal 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
1318
plugins/Clans.cs
Normal file
File diff suppressed because it is too large
Load Diff
693
plugins/CraftingController.cs
Normal file
693
plugins/CraftingController.cs
Normal 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
513
plugins/DiscordAuth.cs
Normal 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
721
plugins/GatherManager.cs
Normal 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
1282
plugins/ImageLibrary.cs
Normal file
File diff suppressed because it is too large
Load Diff
422
plugins/InventoryViewer.cs
Normal file
422
plugins/InventoryViewer.cs
Normal 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
1979
plugins/Kits.cs
Normal file
File diff suppressed because one or more lines are too long
875
plugins/PermissionsManager.cs
Normal file
875
plugins/PermissionsManager.cs
Normal 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
|
||||
}
|
||||
}
|
||||
3392
plugins/PlayerAdministration.cs
Normal file
3392
plugins/PlayerAdministration.cs
Normal file
File diff suppressed because it is too large
Load Diff
519
plugins/QuickSmelt.cs
Normal file
519
plugins/QuickSmelt.cs
Normal 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
1275
plugins/QuickSort.cs
Normal file
File diff suppressed because it is too large
Load Diff
3353
plugins/RemoverTool.cs
Normal file
3353
plugins/RemoverTool.cs
Normal file
File diff suppressed because it is too large
Load Diff
1933
plugins/SkinBox.cs
Normal file
1933
plugins/SkinBox.cs
Normal file
File diff suppressed because it is too large
Load Diff
537
plugins/StackSizeController.cs
Normal file
537
plugins/StackSizeController.cs
Normal 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
355
plugins/TimeOfDay.cs
Normal 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
71
plugins/UnburnableMeat.cs
Normal 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
428
plugins/Vanish.cs
Normal 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
198
plugins/WipeKits.cs
Normal 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
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user