Administrator's Toolkit VS plugin
Revisión | 9e9f04a4367d778dcb2f2d338360533a5c7a7ee2 (tree) |
---|---|
Tiempo | 2020-09-09 08:35:29 |
Autor | melchior <melchior@user...> |
Commiter | melchior |
Added Variable Spawnpoints feature (W.I.P.)
@@ -49,6 +49,11 @@ namespace AdminToolkit | ||
49 | 49 | /// <value>The booming voice.</value> |
50 | 50 | public bool BoomingVoice { get; set; } |
51 | 51 | |
52 | + /// <summary> | |
53 | + /// Semi-Randomize spawn point from a set list | |
54 | + /// </summary> | |
55 | + public bool VariableSpawnpoints { get; set; } | |
56 | + | |
52 | 57 | public AdminModConfig( ) |
53 | 58 | { |
54 | 59 | this.PlayerRoleRestrain = "suvisitor"; |
@@ -76,6 +76,7 @@ | ||
76 | 76 | <Compile Include="Commands\RulesCommand.cs" /> |
77 | 77 | <Compile Include="Commands\BannerControl.cs" /> |
78 | 78 | <Compile Include="Commands\PingerCommand.cs" /> |
79 | + <Compile Include="Commands\VariableSpawnpoints.cs" /> | |
79 | 80 | </ItemGroup> |
80 | 81 | <ItemGroup> |
81 | 82 | <Folder Include="VS_libs\" /> |
@@ -27,6 +27,8 @@ namespace AdminToolkit | ||
27 | 27 | * [DONE] Cyclic automatic Backups |
28 | 28 | * [WIP} Broadcast messages, on a schedule ?????? |
29 | 29 | * [???] Custom Server name : custom formats to indicate server state/time/things |
30 | + * [IDEA]: Player inventory Insurance; recover lost items for a (two) time fee... one policy per player. | |
31 | + * [WIP]: Variable Player (re)Spawn points from a list ~ at random | |
30 | 32 | */ |
31 | 33 | |
32 | 34 | private ICoreAPI API { get; set; } |
@@ -97,8 +99,9 @@ namespace AdminToolkit | ||
97 | 99 | this.ServerAPI.RegisterCommand(new RulesCommand(this.ServerAPI) ); |
98 | 100 | this.ServerAPI.RegisterCommand(new AdminListingCommand(this.ServerAPI) ); |
99 | 101 | this.ServerAPI.RegisterCommand(new BackupCycleCommand(this.ServerAPI) ); |
100 | - this.ServerAPI.RegisterCommand(new BannerControl(this.ServerAPI)); | |
102 | + //this.ServerAPI.RegisterCommand(new BannerControl(this.ServerAPI)); | |
101 | 103 | this.ServerAPI.RegisterCommand(new PingerCommand(this.ServerAPI)); |
104 | + this.ServerAPI.RegisterCommand(new VariableSpawnpoints(this.ServerAPI)); | |
102 | 105 | |
103 | 106 | if (CachedConfiguration.BoomingVoice) { |
104 | 107 | this.ServerAPI.Event.PlayerChat += BoomingVoiceOfAuthority; |
@@ -1,14 +1,20 @@ | ||
1 | 1 | using System; |
2 | +using System.Collections.ObjectModel; | |
2 | 3 | |
3 | 4 | using ProtoBuf; |
4 | 5 | |
5 | 6 | using Vintagestory.API.Common; |
6 | 7 | using Vintagestory.API.Server; |
8 | +using Vintagestory.API.Util; | |
7 | 9 | |
8 | 10 | namespace AdminToolkit |
9 | 11 | { |
10 | 12 | public class BannerControl : AdminModCommand |
11 | 13 | { |
14 | + private const string _bannerDataKey = @"banners"; | |
15 | + | |
16 | + private BannerList Banners { get; set; } | |
17 | + | |
12 | 18 | /// <summary> |
13 | 19 | /// Control and Configuration of automatic Broadcast 'banners' / M.O.T.H. |
14 | 20 | /// </summary> |
@@ -30,17 +36,69 @@ namespace AdminToolkit | ||
30 | 36 | this.Command = "banners"; |
31 | 37 | this.Description = "Control future broadcast 'banners' & repeating Messages"; |
32 | 38 | this.RequiredPrivilege = Privilege.announce; |
39 | + this.Syntax = @"Add / Remove / Replace / List"; | |
33 | 40 | this.handler += HandleBannerCommand; |
34 | 41 | } |
35 | 42 | |
36 | 43 | private void ReactivateBanners( ) |
37 | 44 | { |
45 | + var bannerBytes = ServerAPI.WorldManager.SaveGame.GetData(_bannerDataKey); | |
46 | + | |
47 | + if (bannerBytes != null) { | |
48 | + this.Banners = SerializerUtil.Deserialize<BannerList>(bannerBytes); | |
49 | + Logger.Notification("Loaded Banners Data; ({0})", Banners.Count); | |
50 | + } | |
51 | + else { | |
52 | + BannerList emptyBannerList = new BannerList( ); | |
53 | + | |
54 | + var emptybannerListBytes = SerializerUtil.Serialize<BannerList>(emptyBannerList); | |
55 | + | |
56 | + ServerAPI.WorldManager.SaveGame.StoreData(_bannerDataKey, emptybannerListBytes); | |
57 | + | |
58 | + this.Banners = emptyBannerList; | |
59 | + Logger.Notification("Created (empty) Banners Data"); | |
60 | + } | |
61 | + | |
38 | 62 | |
39 | 63 | } |
40 | 64 | |
41 | 65 | |
42 | 66 | private void HandleBannerCommand(IServerPlayer player, int groupId, CmdArgs args) |
43 | 67 | { |
68 | + | |
69 | + if (args.Length >= 1) { | |
70 | + string cmd = args.PopWord(string.Empty); | |
71 | + switch (cmd.ToLowerInvariant()) | |
72 | + { | |
73 | + //Add <slot#> <repeat/once> <DD:HH:MM:SS> "text" | |
74 | + //Remove <slot#> | |
75 | + //Replace <slot#> "text" | |
76 | + //List | |
77 | + case "add": | |
78 | + | |
79 | + break; | |
80 | + | |
81 | + case "remove": | |
82 | + | |
83 | + break; | |
84 | + | |
85 | + case "replace": | |
86 | + | |
87 | + break; | |
88 | + | |
89 | + case "list": | |
90 | + | |
91 | + break; | |
92 | + | |
93 | + default: | |
94 | + player.SendMessage(groupId, "Unrecognised command ", EnumChatType.CommandError); | |
95 | + break; | |
96 | + | |
97 | + } | |
98 | + } | |
99 | + else { | |
100 | + player.SendMessage(groupId, "Supply a command verb", EnumChatType.CommandError); | |
101 | + } | |
44 | 102 | |
45 | 103 | } |
46 | 104 |
@@ -48,16 +106,37 @@ namespace AdminToolkit | ||
48 | 106 | public struct BannerEntry |
49 | 107 | { |
50 | 108 | [ProtoMember(1)] |
51 | - public string Message; | |
109 | + public byte Entry; | |
52 | 110 | |
53 | 111 | [ProtoMember(2)] |
54 | - public TimeSpan EventTime; | |
112 | + public string Message; | |
55 | 113 | |
56 | 114 | [ProtoMember(3)] |
57 | - public bool Repeat; | |
115 | + public TimeSpan EventTime;//Delay between tick events | |
58 | 116 | |
117 | + [ProtoMember(4)] | |
118 | + public bool Repeat;//Self Re-register on execution of tick event | |
119 | + } | |
59 | 120 | |
121 | + [ProtoContract] | |
122 | + public class BannerList : KeyedCollection<byte, BannerEntry> | |
123 | + { | |
124 | + protected override byte GetKeyForItem(BannerEntry item) | |
125 | + { | |
126 | + return item.Entry; | |
127 | + } | |
128 | + | |
129 | + public void Append(BannerEntry banner) | |
130 | + { | |
131 | + banner.Entry = ( byte )this.Count; | |
132 | + Add(banner); | |
133 | + } | |
134 | + | |
135 | + private new void Add(BannerEntry item) | |
136 | + { | |
137 | + //Not directly. | |
138 | + } | |
60 | 139 | } |
61 | -} | |
140 | + } | |
62 | 141 | } |
63 | 142 |
@@ -0,0 +1,243 @@ | ||
1 | +using System; | |
2 | +using System.Linq; | |
3 | +using System.Collections.Generic; | |
4 | + | |
5 | +using Vintagestory.API.Common; | |
6 | +using Vintagestory.API.Config; | |
7 | +using Vintagestory.API.MathTools; | |
8 | +using Vintagestory.API.Server; | |
9 | +using Vintagestory.API.Util; | |
10 | + | |
11 | +using Vintagestory.Server; | |
12 | + | |
13 | +using ProtoBuf; | |
14 | + | |
15 | + | |
16 | +namespace AdminToolkit | |
17 | +{ | |
18 | + [ProtoContract] | |
19 | + public struct Spawnpoint | |
20 | + { | |
21 | + [ProtoMember(1)] | |
22 | + public PlayerSpawnPos Location; | |
23 | + | |
24 | + [ProtoMember(2)] | |
25 | + public string Name; | |
26 | + | |
27 | + public Spawnpoint(string name, Vec3i loc) | |
28 | + { | |
29 | + Name = name; | |
30 | + Location = new PlayerSpawnPos { | |
31 | + x = loc.X, | |
32 | + y = loc.Y, | |
33 | + z = loc.Z | |
34 | + }; | |
35 | + } | |
36 | + | |
37 | + } | |
38 | + | |
39 | + public class VariableSpawnpoints : AdminModCommand | |
40 | + { | |
41 | + private const string _spawnsDataKey = @"spawnpoints"; | |
42 | + private Random random = new Random(); | |
43 | + | |
44 | + private List<Spawnpoint> Spawnpoints { get; set; } | |
45 | + | |
46 | + | |
47 | + public VariableSpawnpoints(ICoreServerAPI _serverAPI) : base(_serverAPI) | |
48 | + { | |
49 | + this.Command = "spawnpoints"; | |
50 | + this.Description = "Control add/remove/adjust List of approved player spawn points"; | |
51 | + this.RequiredPrivilege = Privilege.setspawn; | |
52 | + this.Syntax = @"Add {name} {123,456,-678}|here / Remove {name} / List / Enable / Disable"; | |
53 | + this.handler += HandleCommand; | |
54 | + | |
55 | + ServerAPI.Event.ServerRunPhase(EnumServerRunPhase.RunGame, ReloadSpawnpoints); | |
56 | + ServerAPI.Event.PlayerCreate += NewPlayerCreation; | |
57 | + ServerAPI.Event.PlayerDeath += PlayerDied; | |
58 | + ServerAPI.Event.ServerRunPhase(EnumServerRunPhase.Shutdown, PersistSpawnpoints); | |
59 | + } | |
60 | + | |
61 | + private void ReloadSpawnpoints( ) | |
62 | + { | |
63 | + var spawnsBytes = ServerAPI.WorldManager.SaveGame.GetData(_spawnsDataKey); | |
64 | + | |
65 | + if (spawnsBytes != null) { | |
66 | + this.Spawnpoints = SerializerUtil.Deserialize<List<Spawnpoint>>(spawnsBytes); | |
67 | + Logger.Notification("Loaded Variable-Spawns # ({0})", Spawnpoints.Count); | |
68 | + } | |
69 | + else { | |
70 | + this.Spawnpoints = new List<Spawnpoint>( ); | |
71 | + | |
72 | + var emptySpawnsList = SerializerUtil.Serialize(this.Spawnpoints); | |
73 | + | |
74 | + ServerAPI.WorldManager.SaveGame.StoreData(_spawnsDataKey, emptySpawnsList); | |
75 | + | |
76 | + Logger.Notification("Created (empty) Spawnpoints Data"); | |
77 | + } | |
78 | + | |
79 | + | |
80 | + } | |
81 | + | |
82 | + private void PersistSpawnpoints( ) | |
83 | + { | |
84 | + if (this.Spawnpoints != null && this.Spawnpoints.Count > 0) { | |
85 | + var spawnDatas = SerializerUtil.Serialize(this.Spawnpoints); | |
86 | + ServerAPI.WorldManager.SaveGame.StoreData(_spawnsDataKey, spawnDatas); | |
87 | + Logger.Notification("Persisted Spawnpoints Data"); | |
88 | + } | |
89 | + | |
90 | + } | |
91 | + | |
92 | + private void HandleCommand(IServerPlayer player, int groupId, CmdArgs args) | |
93 | + { | |
94 | + string name; | |
95 | + Vec3i position; | |
96 | + | |
97 | + | |
98 | + | |
99 | + if (args.Length >= 1) { | |
100 | + string cmd = args.PopWord(string.Empty).ToLowerInvariant(); | |
101 | + switch (cmd) { | |
102 | + | |
103 | + case "add": | |
104 | + name = args.PopWord("?"); | |
105 | + | |
106 | + if (String.Equals(args.PeekWord(), "here", StringComparison.OrdinalIgnoreCase)) { | |
107 | + position = player.Entity.Pos.XYZInt; | |
108 | + } | |
109 | + position = args.PopVec3i(player.Entity.Pos.XYZInt); | |
110 | + if (AddSpawnpoint(name, position)) { | |
111 | + player.SendMessage(groupId, "Added Spawnpoint", EnumChatType.CommandSuccess); | |
112 | + } | |
113 | + break; | |
114 | + | |
115 | + case "remove": | |
116 | + name = args.PopWord( ); | |
117 | + if (RemoveSpawnpoint(name)) { | |
118 | + player.SendMessage(groupId, "Removed Spawnpoint", EnumChatType.CommandSuccess); | |
119 | + } | |
120 | + break; | |
121 | + | |
122 | + case "list": | |
123 | + ListSpawnpoints(groupId, player); | |
124 | + break; | |
125 | + | |
126 | + case "enable": | |
127 | + Toggle(true); | |
128 | + break; | |
129 | + | |
130 | + case "disable": | |
131 | + Toggle(false); | |
132 | + break; | |
133 | + | |
134 | + default: | |
135 | + player.SendMessage(groupId, "Unrecognised command ", EnumChatType.CommandError); | |
136 | + break; | |
137 | + | |
138 | + } | |
139 | + } | |
140 | + else { | |
141 | + player.SendMessage(groupId, "Supply a command verb", EnumChatType.CommandError); | |
142 | + } | |
143 | + | |
144 | + } | |
145 | + | |
146 | + private bool AddSpawnpoint(string name, Vec3i position) | |
147 | + { | |
148 | + //Check position is 'safe'; 2~ blocks air, and solid block BELOW... | |
149 | + var surfaceBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AsBlockPos); | |
150 | + var aboveBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AddCopy(BlockFacing.UP).AsBlockPos); | |
151 | + var belowBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AddCopy(BlockFacing.DOWN).AsBlockPos); | |
152 | + | |
153 | + if (belowBlock.MatterState == EnumMatterState.Solid && | |
154 | + aboveBlock.BlockMaterial == EnumBlockMaterial.Air && | |
155 | + surfaceBlock.BlockMaterial == EnumBlockMaterial.Air) { | |
156 | + //Appears OK... | |
157 | + Logger.VerboseDebug($"Adding variable spawnpoint '{name}' @ {position}"); | |
158 | + var newSpawnpoint = new Spawnpoint(name, position); | |
159 | + | |
160 | + this.Spawnpoints.Add(newSpawnpoint); | |
161 | + return true; | |
162 | + } | |
163 | + else { | |
164 | + Logger.VerboseDebug($"Apparently spawnpoint Unsafe! @ {position}"); | |
165 | + } | |
166 | + | |
167 | + return false; | |
168 | + } | |
169 | + | |
170 | + private bool RemoveSpawnpoint(string name) | |
171 | + { | |
172 | + | |
173 | + if (this.Spawnpoints.Count > 0) { | |
174 | + var count = this.Spawnpoints.RemoveAll(sp => String.Equals(sp.Name, name, StringComparison.InvariantCultureIgnoreCase)); | |
175 | + return count > 0; | |
176 | + } | |
177 | + | |
178 | + return false; | |
179 | + } | |
180 | + | |
181 | + private void ListSpawnpoints( int chatGroupId, IServerPlayer player ) | |
182 | + { | |
183 | + if (this.Spawnpoints.Count > 0) { | |
184 | + foreach (var sp in this.Spawnpoints) { | |
185 | + player.SendMessage(chatGroupId, $"Spawn: '{sp.Name}' @({sp.Location})", EnumChatType.CommandSuccess); | |
186 | + } | |
187 | + } | |
188 | + } | |
189 | + | |
190 | + private void Toggle(bool state) | |
191 | + { | |
192 | + this.CachedConfiguration.VariableSpawnpoints = state; | |
193 | + } | |
194 | + | |
195 | + private void NewPlayerCreation( IServerPlayer byPlayer) | |
196 | + { | |
197 | + if (this.CachedConfiguration.VariableSpawnpoints && this.Spawnpoints.Count > 0) { | |
198 | + | |
199 | + var swpd = byPlayer.WorldData as ServerWorldPlayerData; | |
200 | + if (swpd.SpawnPosition == null) { | |
201 | + var newSP = RandomSpawnpoint( ); | |
202 | + byPlayer.SetSpawnPosition(newSP.Location); | |
203 | + #if DEBUG | |
204 | + Logger.VerboseDebug($"New spawn Pos: '{newSP.Name}' @ {newSP.Location} "); | |
205 | + #endif | |
206 | + } | |
207 | + } | |
208 | + } | |
209 | + | |
210 | + private void PlayerDied(IServerPlayer byPlayer, DamageSource damageSource) | |
211 | + { | |
212 | + if (this.CachedConfiguration.VariableSpawnpoints && this.Spawnpoints.Count > 0) { | |
213 | + | |
214 | + var swpd = byPlayer.WorldData as ServerWorldPlayerData; | |
215 | + if (swpd.SpawnPosition == null || KnownSpawn(swpd.SpawnPosition)) { | |
216 | + var newSP = RandomSpawnpoint( ); | |
217 | + byPlayer.SetSpawnPosition(newSP.Location); | |
218 | + #if DEBUG | |
219 | + Logger.VerboseDebug( $"Changed spawn Pos: '{newSP.Name}' @ {newSP.Location} "); | |
220 | + #endif | |
221 | + } | |
222 | + } | |
223 | + } | |
224 | + | |
225 | + private Spawnpoint RandomSpawnpoint( ) | |
226 | + { | |
227 | + return this.Spawnpoints[random.Next(0, Spawnpoints.Count - 1)]; | |
228 | + } | |
229 | + | |
230 | + private bool KnownSpawn(PlayerSpawnPos aSpawn) | |
231 | + { | |
232 | + if (this.Spawnpoints.Count > 0) { | |
233 | + return this.Spawnpoints.Any(vsps => vsps.Location.x == aSpawn.x | |
234 | + && vsps.Location.y == aSpawn.y | |
235 | + && vsps.Location.z == aSpawn.z); | |
236 | + } | |
237 | + | |
238 | + return false; | |
239 | + } | |
240 | + } | |
241 | +} | |
242 | + | |
243 | + |
@@ -1,11 +1,11 @@ | ||
1 | 1 | { |
2 | 2 | "type": "code", |
3 | 3 | "name": "Administrator's Toolkit mod", |
4 | - "description" : "Provides misc. Admin functions;\n list admins, print & accept rules (multi-lingual) , auto-backup...", | |
4 | + "description" : "Provides misc. Admin functions;\n admin listing, rules display (multi-lingual), auto-backup & more...", | |
5 | 5 | "authors": ["Melchior", ], |
6 | - "version": "0.3.5", | |
6 | + "version": "0.3.6", | |
7 | 7 | "dependencies": { |
8 | - "game": "1.12.4" | |
8 | + "game": "1.13.0" | |
9 | 9 | }, |
10 | 10 | "requiredonclient":false, |
11 | 11 | "website": "https://osdn.net/users/melchior/pf/admintoolkit/" |