Administrator's Toolkit VS plugin
Revisão | cfaa5f6506f37db7a05ae4bcfa7aef5a6d737581 (tree) |
---|---|
Hora | 2020-12-17 10:39:47 |
Autor | melchior <melchior@user...> |
Commiter | melchior |
D.I.Y. Multi-Lingual support, and to support i18n
@@ -86,8 +86,8 @@ namespace AdminToolkit | ||
86 | 86 | //Annonce to all players that Admin\Moderator has arrived |
87 | 87 | |
88 | 88 | StringBuilder adminMessage = new StringBuilder( ); |
89 | - | |
90 | - adminMessage.AppendFormat("<font color='{1}' weight='bold'>«{0}» {2}</font> Present.", byPlayer.Role.Name, byPlayer.Role.Color.Name, byPlayer.PlayerName); | |
89 | + | |
90 | + adminMessage.Append(MultiLang.Get(byPlayer, @"atk:admin_present",byPlayer.Role.Name, byPlayer.Role.Color.Name, byPlayer.PlayerName)); | |
91 | 91 | |
92 | 92 | ServerAPI.SendMessageToGroup(GlobalConstants.AllChatGroups, adminMessage.ToString( ), EnumChatType.AllGroups); |
93 | 93 |
@@ -104,7 +104,7 @@ namespace AdminToolkit | ||
104 | 104 | var playerPos = byPlayer.Entity.Pos.AsBlockPos.Copy(); |
105 | 105 | |
106 | 106 | //No Localized Season/Hemispehere names? |
107 | - string welcomebackMsg = Lang.Get(@"welcomeback-message", | |
107 | + string welcomebackMsg = MultiLang.Get(byPlayer, @"atk:welcomeback-message", | |
108 | 108 | elapsedDays, |
109 | 109 | ServerAPI.World.AllOnlinePlayers.Length, |
110 | 110 | ServerAPI.World.Calendar.GetSeason(playerPos), |
@@ -114,7 +114,7 @@ namespace AdminToolkit | ||
114 | 114 | byPlayer.SendMessage(GlobalConstants.CurrentChatGroup, welcomebackMsg, EnumChatType.OthersMessage); |
115 | 115 | } |
116 | 116 | else { |
117 | - string welcomeMsg = Lang.Get(@"welcome-message", | |
117 | + string welcomeMsg = MultiLang.Get(byPlayer, @"atk:welcome-message", | |
118 | 118 | ServerAPI.World.Calendar.PrettyDate( ) |
119 | 119 | ); |
120 | 120 | byPlayer.SendMessage(GlobalConstants.CurrentChatGroup,welcomeMsg, EnumChatType.OthersMessage); |
@@ -124,13 +124,6 @@ namespace AdminToolkit | ||
124 | 124 | |
125 | 125 | |
126 | 126 | } |
127 | - | |
128 | - /* Something like: | |
129 | - | |
130 | - string GetLang(string key, string langCode, params object[ ] parameters) //No fallback | |
131 | - string GetLang_Fallback(string key, string langCode, params object[ ] parameters) //Uses 'Local' language for missing key | |
132 | - | |
133 | - */ | |
134 | 127 | } |
135 | 128 | } |
136 | 129 |
@@ -82,7 +82,7 @@ | ||
82 | 82 | <Compile Include="Commands\PingerCommand.cs" /> |
83 | 83 | <Compile Include="Commands\VariableSpawnpoints.cs" /> |
84 | 84 | <Compile Include="ATK_BasicFeatures.cs" /> |
85 | - <Compile Include="MultiLang.cs" /> | |
85 | + <Compile Include="Helpers\MultiLang.cs" /> | |
86 | 86 | </ItemGroup> |
87 | 87 | <ItemGroup> |
88 | 88 | <Folder Include="VS_libs\" /> |
@@ -90,6 +90,7 @@ | ||
90 | 90 | <Folder Include="assets\" /> |
91 | 91 | <Folder Include="assets\atk\" /> |
92 | 92 | <Folder Include="assets\atk\lang\" /> |
93 | + <Folder Include="Helpers\" /> | |
93 | 94 | </ItemGroup> |
94 | 95 | <ItemGroup> |
95 | 96 | <None Include="modinfo.json"> |
@@ -100,6 +101,7 @@ | ||
100 | 101 | <None Include="assets\atk\lang\en.json"> |
101 | 102 | <CopyToOutputDirectory>Always</CopyToOutputDirectory> |
102 | 103 | </None> |
104 | + <None Include="MultiLang.cs" /> | |
103 | 105 | </ItemGroup> |
104 | 106 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
105 | 107 | </Project> |
\ No newline at end of file |
@@ -101,6 +101,9 @@ namespace AdminToolkit | ||
101 | 101 | PopulateAdminRoleTable( ); |
102 | 102 | PrepareServersideConfig( ); |
103 | 103 | |
104 | + MultiLang.Load(Mod.Logger, ServerAPI.Assets, Mod.Info.ModID); | |
105 | + | |
106 | + | |
104 | 107 | if (this.CachedConfiguration.RuleRoleChangerEnabled) { this.ServerAPI.RegisterCommand(new RulesCommand(this.ServerAPI)); } |
105 | 108 | this.ServerAPI.RegisterCommand(new AdminListingCommand(this.ServerAPI) ); |
106 | 109 | this.ServerAPI.RegisterCommand(new BackupCycleCommand(this.ServerAPI) ); |
@@ -32,13 +32,13 @@ namespace AdminToolkit | ||
32 | 32 | msgLine.AppendFormat("<font color='{2}'>[{0}]</font> -- \"{1}\" ", srvPlayer.Role.Name, playerName, srvPlayer.Role.Color.Name); |
33 | 33 | |
34 | 34 | if (srvPlayer.ConnectionState == EnumClientState.Playing) { |
35 | - msgLine.AppendFormat("IS: <font color='lime'>*{0}*</font>", srvPlayer.ConnectionState); | |
35 | + msgLine.AppendFormat("· <font color='lime'>*{0}*</font>", srvPlayer.ConnectionState); | |
36 | 36 | } else { |
37 | - msgLine.AppendFormat("IS: <font color='yellow'>{0}</font>", srvPlayer.ConnectionState); | |
37 | + msgLine.AppendFormat("· <font color='yellow'>{0}</font>", srvPlayer.ConnectionState); | |
38 | 38 | } |
39 | 39 | |
40 | 40 | if (srvPlayer.ServerData.CustomPlayerData.ContainsKey(AdminToolkit._lastLoginKey)) { |
41 | - msgLine.AppendFormat(" Last Login: {0}", srvPlayer.ServerData.CustomPlayerData[AdminToolkit._lastLoginKey]); | |
41 | + msgLine.AppendFormat("\tΔ : {0}", srvPlayer.ServerData.CustomPlayerData[AdminToolkit._lastLoginKey]); | |
42 | 42 | } |
43 | 43 | msgLine.AppendLine( ); |
44 | 44 | } |
@@ -122,10 +122,10 @@ namespace AdminToolkit | ||
122 | 122 | |
123 | 123 | PlayerAcceptsRulesAction( player); |
124 | 124 | } else { |
125 | - player.SendMessage(groupId, $"{player.PlayerName} ALREADY ACCEPTED RULES!", EnumChatType.CommandSuccess); | |
125 | + player.SendMessage(groupId, MultiLang.Get(player, "atk:already-accept",player.PlayerName), EnumChatType.CommandSuccess); | |
126 | 126 | } |
127 | 127 | } else { |
128 | - player.SendMessage(groupId, $"{player.PlayerName} type in chat console: /rules {_acceptKeyword}", EnumChatType.CommandError); | |
128 | + player.SendMessage(groupId, MultiLang.Get(player, "atk:type-chat-rules", player.PlayerName ,_acceptKeyword), EnumChatType.CommandError); | |
129 | 129 | } |
130 | 130 | |
131 | 131 | } else { |
@@ -139,7 +139,7 @@ namespace AdminToolkit | ||
139 | 139 | } |
140 | 140 | } else { |
141 | 141 | //Subsitute rules? |
142 | - player.SendMessage(groupId, $"* MISSING RULES FILE ({targetLocale})! *", EnumChatType.CommandError); | |
142 | + player.SendMessage(groupId, MultiLang.Get(player, "atk:missing-rules", targetLocale), EnumChatType.CommandError); | |
143 | 143 | } |
144 | 144 | } |
145 | 145 | } |
@@ -154,7 +154,7 @@ namespace AdminToolkit | ||
154 | 154 | //For regular players |
155 | 155 | if (RulesCommand.CheckRuleAccepted(byPlayer) == false) { |
156 | 156 | //TODO: localize |
157 | - byPlayer.SendMessage(GlobalConstants.CurrentChatGroup, "type ' /rules ' command for reading server rules.", EnumChatType.Notification); | |
157 | + byPlayer.SendMessage(GlobalConstants.CurrentChatGroup, MultiLang.GetUnformatted(byPlayer,"atk:type-rules"), EnumChatType.Notification); | |
158 | 158 | |
159 | 159 | if (this.CachedConfiguration.RuleRoleChangerEnabled) { |
160 | 160 | PlayerNeverAcceptedRulesAction(byPlayer); |
@@ -165,7 +165,7 @@ namespace AdminToolkit | ||
165 | 165 | |
166 | 166 | private void PlayerAcceptsRulesAction(IServerPlayer byPlayer ) |
167 | 167 | { |
168 | - ServerAPI.BroadcastMessageToAllGroups($"{byPlayer.PlayerName} HAS ACCEPTED THE RULES!", EnumChatType.CommandSuccess); | |
168 | + ServerAPI.BroadcastMessageToAllGroups(MultiLang.Get(byPlayer,"atk:accepted-rules", byPlayer.PlayerName), EnumChatType.CommandSuccess); | |
169 | 169 | byPlayer.ServerData.CustomPlayerData[_ruleAcceptKey] = true.ToString( ); |
170 | 170 | ServerAPI.Server.LogNotification($"Player:{byPlayer.PlayerName} UID: {byPlayer.PlayerUID} HAS ACCEPTED RULES @ {DateTime.Now.ToShortDateString( )}"); |
171 | 171 |
@@ -176,7 +176,7 @@ namespace AdminToolkit | ||
176 | 176 | |
177 | 177 | ServerAPI.Permissions.SetRole(byPlayer, normalRole.Code); |
178 | 178 | Logger.Notification("Player {0} accepted the rules, and was promoted to role: {1}", byPlayer.PlayerName, byPlayer.Role.Name); |
179 | - byPlayer.SendMessage(GlobalConstants.GeneralChatGroup, $"{byPlayer.PlayerName} have been promoted to: {byPlayer.Role.Name}", EnumChatType.OthersMessage); | |
179 | + byPlayer.SendMessage(GlobalConstants.GeneralChatGroup, MultiLang.Get(byPlayer, "atk:promoted-to", byPlayer.PlayerName, byPlayer.Role.Name), EnumChatType.OthersMessage); | |
180 | 180 | } else { |
181 | 181 | Logger.Debug("Role change process did not complete; not enabled or mis-configured"); |
182 | 182 | } |
@@ -191,7 +191,7 @@ namespace AdminToolkit | ||
191 | 191 | |
192 | 192 | ServerAPI.Permissions.SetRole(byPlayer, restrainRole.Code); |
193 | 193 | Logger.Notification("Player {0} never accepted rules, and was demoted to role: {1}", byPlayer.PlayerName, byPlayer.Role.Name); |
194 | - byPlayer.SendMessage(GlobalConstants.GeneralChatGroup, $"{byPlayer.PlayerName} have been demoted to: {byPlayer.Role.Name}", EnumChatType.OthersMessage); | |
194 | + byPlayer.SendMessage(GlobalConstants.GeneralChatGroup, MultiLang.Get(byPlayer, "atk:demoted-to", byPlayer.PlayerName, byPlayer.Role.Name), EnumChatType.OthersMessage); | |
195 | 195 | } |
196 | 196 | } |
197 | 197 | } |
@@ -137,14 +137,7 @@ namespace AdminToolkit | ||
137 | 137 | |
138 | 138 | private bool AddSpawnpoint(string name, Vec3i position) |
139 | 139 | { |
140 | - //Check position is 'safe'; 2~ blocks air, and solid block BELOW... | |
141 | - var surfaceBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AsBlockPos); | |
142 | - var aboveBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AddCopy(BlockFacing.UP).AsBlockPos); | |
143 | - var belowBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AddCopy(BlockFacing.DOWN).AsBlockPos); | |
144 | - | |
145 | - if (belowBlock.MatterState == EnumMatterState.Solid && | |
146 | - aboveBlock.BlockMaterial == EnumBlockMaterial.Air && | |
147 | - surfaceBlock.BlockMaterial == EnumBlockMaterial.Air) { | |
140 | + if (IsItSafe(position.AsBlockPos)) { | |
148 | 141 | //Appears OK... |
149 | 142 | Logger.VerboseDebug($"Adding variable spawnpoint '{name}' @ {position}"); |
150 | 143 | var newSpawnpoint = new Spawnpoint(name, position); |
@@ -159,6 +152,27 @@ namespace AdminToolkit | ||
159 | 152 | return false; |
160 | 153 | } |
161 | 154 | |
155 | + private bool IsItSafe(BlockPos position) | |
156 | + { | |
157 | + //Check position is 'safe'; 2~ blocks airish, and solid block BELOW... | |
158 | + var surfaceBlock = ServerAPI.World.BlockAccessor.GetBlock(position); | |
159 | + var aboveBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AddCopy(BlockFacing.UP)); | |
160 | + var belowBlock = ServerAPI.World.BlockAccessor.GetBlock(position.AddCopy(BlockFacing.DOWN)); | |
161 | + | |
162 | + if (belowBlock.MatterState == EnumMatterState.Solid && | |
163 | + aboveBlock.BlockMaterial == EnumBlockMaterial.Air && | |
164 | + surfaceBlock.BlockMaterial == EnumBlockMaterial.Air | |
165 | + || surfaceBlock.BlockMaterial == EnumBlockMaterial.Snow | |
166 | + || surfaceBlock.BlockMaterial == EnumBlockMaterial.Liquid | |
167 | + || surfaceBlock.BlockMaterial == EnumBlockMaterial.Leaves | |
168 | + ) | |
169 | + { | |
170 | + return true; | |
171 | + } | |
172 | + | |
173 | + return false; | |
174 | + } | |
175 | + | |
162 | 176 | private bool RemoveSpawnpoint(string name) |
163 | 177 | { |
164 | 178 |
@@ -0,0 +1,120 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Collections.ObjectModel; | |
4 | +using System.Linq; | |
5 | +using System.Text.RegularExpressions; | |
6 | + | |
7 | +using Newtonsoft.Json; | |
8 | + | |
9 | +using Vintagestory.API.Common; | |
10 | +using Vintagestory.API.Server; | |
11 | +using Vintagestory.Client.NoObf; | |
12 | + | |
13 | +namespace AdminToolkit | |
14 | +{ | |
15 | + public static class MultiLang | |
16 | + { | |
17 | + public static LanguageSet LanguageSets; | |
18 | + public static string[ ] SupportedCodes { get; private set;} | |
19 | + | |
20 | + | |
21 | + public static void Load(ILogger logger, IAssetManager ownAssetMgr, string domain) | |
22 | + { | |
23 | + #if DEBUG | |
24 | + logger.VerboseDebug("Preparing to load Multi-Linugal data; for '{0}'", domain); | |
25 | + #endif | |
26 | + | |
27 | + List<IAssetOrigin> origins = ownAssetMgr.Origins; | |
28 | + LanguageSets = new LanguageSet( ); | |
29 | + | |
30 | + GuiCompositeSettings.LanguageConfig[] supportedLangs = ownAssetMgr.Get<GuiCompositeSettings.LanguageConfig[]>(new AssetLocation("lang/languages.json")); | |
31 | + SupportedCodes = supportedLangs.Select(sl => sl.Code).ToArray( );//{ "en", "de", "it", "fr", "pt-br", "ru" }; | |
32 | + | |
33 | + List<IAsset> languageAssets = ownAssetMgr.GetMany(@"lang/", domain, true); | |
34 | + foreach (var asset in languageAssets) { | |
35 | + try { | |
36 | + LanguageSets.Add(new LangEntry(asset)); | |
37 | + #if DEBUG | |
38 | + logger.VerboseDebug("Appended M.l. Dicts: with '{0}'", asset.Name); | |
39 | + #endif | |
40 | + } catch (Exception e) { | |
41 | + logger.Error("Failed to process multi-lang file {0}: {1}", asset.Location, e); | |
42 | + } | |
43 | + } | |
44 | + } | |
45 | + | |
46 | + | |
47 | + | |
48 | + public static string Get(string langCode, string key, params object[] formaters) | |
49 | + { | |
50 | + if (LanguageSets.Contains(langCode)) | |
51 | + { | |
52 | + LangEntry langD = LanguageSets[langCode]; | |
53 | + if (langD.LangEntries.ContainsKey(key)) { | |
54 | + return string.Format(langD.LangEntries[key], formaters); | |
55 | + } | |
56 | + } | |
57 | + return key; | |
58 | + } | |
59 | + | |
60 | + public static string Get(IServerPlayer byPlayerLang, string key, params object[ ] formaters) | |
61 | + { | |
62 | + if (LanguageSets.Contains(byPlayerLang.LanguageCode)) { | |
63 | + LangEntry langD = LanguageSets[byPlayerLang.LanguageCode]; | |
64 | + if (langD.LangEntries.ContainsKey(key)) { | |
65 | + return string.Format(langD.LangEntries[key], formaters); | |
66 | + } | |
67 | + } | |
68 | + return key; | |
69 | + } | |
70 | + | |
71 | + public static string GetUnformatted(IServerPlayer byPlayerLang, string key) | |
72 | + { | |
73 | + if (LanguageSets.Contains(byPlayerLang.LanguageCode)) { | |
74 | + LangEntry langD = LanguageSets[byPlayerLang.LanguageCode]; | |
75 | + if (langD.LangEntries.ContainsKey(key)) { | |
76 | + return langD.LangEntries[key]; | |
77 | + } | |
78 | + } | |
79 | + return key; | |
80 | + } | |
81 | + } | |
82 | + | |
83 | + public class LanguageSet : KeyedCollection<string, LangEntry> | |
84 | + { | |
85 | + protected override string GetKeyForItem(LangEntry item) | |
86 | + { | |
87 | + return item.Code; | |
88 | + } | |
89 | + } | |
90 | + | |
91 | + public struct LangEntry | |
92 | + { | |
93 | + public Dictionary<string, string> LangEntries; | |
94 | + //public Dictionary<string, KeyValuePair<Regex, string>> LangRegexes; | |
95 | + //public Dictionary<string, string> LangStartsWith; | |
96 | + public readonly string Code; | |
97 | + | |
98 | + public LangEntry( string langCode = "en") | |
99 | + { | |
100 | + LangEntries = new Dictionary<string, string>( ); | |
101 | + //LangRegexes = new Dictionary<string, KeyValuePair<Regex, string>>( ); | |
102 | + //LangStartsWith = new Dictionary<string, string>( ); | |
103 | + Code = langCode; | |
104 | + } | |
105 | + | |
106 | + public LangEntry(IAsset langAsset) | |
107 | + { | |
108 | + if (langAsset.IsLoaded( )) { | |
109 | + LangEntries = JsonConvert.DeserializeObject<Dictionary<string, string>>(langAsset.ToText( )); | |
110 | + } | |
111 | + else { | |
112 | + LangEntries = new Dictionary<string, string>( ); | |
113 | + } | |
114 | + //LangRegexes = new Dictionary<string, KeyValuePair<Regex, string>>( ); | |
115 | + //LangStartsWith = new Dictionary<string, string>( ); | |
116 | + Code = langAsset.Name.Split('.').First( ); | |
117 | + } | |
118 | + } | |
119 | +} | |
120 | + |
@@ -1,12 +1,13 @@ | ||
1 | 1 | { |
2 | - "welcomeback-message": "Meantime... {0:F1} days have passed. {1} Players online. It is {2} in the {3}.", | |
3 | - "welcome-message":"In the year; {0}", | |
4 | - "display-rules":"Display server Rules", | |
5 | - "already-accept":"{0} ALREADY ACCEPTED RULES!", | |
6 | - "type-chat-rules":"{0} type in chat console: /rules {1}", | |
7 | - "missing-rules":"* MISSING RULES FILE ({0})! *", | |
8 | - "type-rules":"type ' /rules ' command for reading server rules.", | |
9 | - "accepted-rules":"{0} HAS ACCEPTED THE RULES!", | |
10 | - "promoted-to":"{0} have been promoted to: {1}", | |
11 | - "demoted-to":"{0} have been demoted to: {1}", | |
2 | + "atk:admin_present":"<font color='{1}' weight='bold'>«{0}» {2}</font> Present.", | |
3 | + "atk:welcomeback-message": "Meantime... {0:F1} days have passed. {1} Players online. It is {2} in the {3}.", | |
4 | + "atk:welcome-message":"In the year; {0}", | |
5 | + "atk:display-rules":"Display server Rules", | |
6 | + "atk:already-accept":"{0} ALREADY ACCEPTED RULES!", | |
7 | + "atk:type-chat-rules":"{0} type in chat console: /rules {1}", | |
8 | + "atk:missing-rules":"* MISSING RULES FILE ({0})! *", | |
9 | + "atk:type-rules":"type ' /rules ' command for reading server rules.", | |
10 | + "atk:accepted-rules":"{0} HAS ACCEPTED THE RULES!", | |
11 | + "atk:promoted-to":"{0} have been promoted to: {1}", | |
12 | + "atk:demoted-to":"{0} have been demoted to: {1}", | |
12 | 13 | } |
@@ -6,7 +6,7 @@ | ||
6 | 6 | "authors": ["Melchior", ], |
7 | 7 | "version": "0.3.6", |
8 | 8 | "dependencies": { |
9 | - "game": "1.13.4" | |
9 | + "game": "1.14.0" | |
10 | 10 | }, |
11 | 11 | "requiredonclient":false, |
12 | 12 | "website": "https://osdn.net/users/melchior/pf/admintoolkit/" |