Skip to content

Commit 19ae918

Browse files
committed
Improve forced-unicode locale support, and more
* Dynamic char width calculation based on vanilla assets * allow chatui to be disabled * borderless table renderer
1 parent d8443d0 commit 19ae918

34 files changed

+684
-415
lines changed
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package com.simon816.chatui;
2+
3+
import com.google.common.base.Objects;
4+
import com.simon816.chatui.impl.ImplementationConfig;
5+
import com.simon816.chatui.tabs.GlobalTab;
6+
import com.simon816.chatui.tabs.NewTab;
7+
import com.simon816.chatui.tabs.PermissionsTab;
8+
import com.simon816.chatui.tabs.SceneTab;
9+
import com.simon816.chatui.tabs.Tab;
10+
import com.simon816.chatui.tabs.TextBufferTab;
11+
import com.simon816.chatui.tabs.TextFileTab;
12+
import com.simon816.chatui.tabs.config.ConfigEditTab;
13+
import ninja.leaping.configurate.ConfigurationNode;
14+
import org.spongepowered.api.command.CommandSource;
15+
import org.spongepowered.api.entity.living.player.Player;
16+
import org.spongepowered.api.text.Text;
17+
import org.spongepowered.api.text.chat.ChatType;
18+
19+
import java.util.Optional;
20+
import java.util.UUID;
21+
22+
public class ActivePlayerChatView implements PlayerChatView {
23+
24+
private PlayerContext playerContext;
25+
private final Window window;
26+
private final TextBufferTab globalTab;
27+
private final NewTab newTab;
28+
boolean isUpdating;
29+
30+
private final PlayerList playerList;
31+
32+
ActivePlayerChatView(Player player, ConfigurationNode settings) {
33+
this.playerContext = new PlayerContext(player,
34+
settings.getNode("displayWidth").getInt(),
35+
settings.getNode("displayHeight").getInt(),
36+
settings.getNode("forceUnicode").getBoolean());
37+
this.window = new Window();
38+
this.window.addTab(this.globalTab = new GlobalTab(), true);
39+
this.newTab = new NewTab();
40+
this.playerList = new PlayerList(player);
41+
initNewTab(player);
42+
ChatUI.instance().loadFeatures(this);
43+
}
44+
45+
@Override
46+
public PlayerList getPlayerList() {
47+
return this.playerList;
48+
}
49+
50+
private void initNewTab(Player player) {
51+
this.newTab.addButton("Player List", new NewTab.LaunchTabAction(() -> new SceneTab(Text.of("Player List"), this.playerList.getRoot())));
52+
UUID uuid = player.getUniqueId();
53+
this.newTab.addButton("Settings", new NewTab.LaunchTabAction(() -> createSettingsTab(uuid)));
54+
if (player.hasPermission(ChatUI.ADMIN_PERMISSON)) {
55+
showNewTabAdminButtons();
56+
}
57+
if (DemoContent.ENABLE_DEMO) {
58+
this.newTab.addButton("Demo Content", new NewTab.LaunchTabAction(() -> DemoContent.TAB));
59+
}
60+
}
61+
62+
private Tab createSettingsTab(UUID uuid) {
63+
ConfigurationNode config = Config.playerConfig(uuid);
64+
ConfigEditTab.Options opts = new ConfigEditTab.Options(false, true, false, "Settings");
65+
ConfigEditTab.ActionHandler handler = new ConfigEditTab.ActionHandler() {
66+
67+
@Override
68+
public void onNodeChanged(ConfigurationNode node) {
69+
Config.saveConfig();
70+
onConfigChange(node);
71+
}
72+
};
73+
return new ConfigEditTab(config, Text.of("Settings"), opts, handler);
74+
}
75+
76+
private void showNewTabAdminButtons() {
77+
if (ImplementationConfig.isSupported()) {
78+
this.newTab.addButton("Edit Config", new NewTab.LaunchTabAction(() -> new ConfigEditTab(ImplementationConfig.getRootNode(),
79+
Text.of("Sponge Config"), ConfigEditTab.Options.DEFAULTS, ImplementationConfig.getHandler())));
80+
}
81+
this.newTab.addButton("Permissions", new NewTab.LaunchTabAction(() -> new PermissionsTab()));
82+
}
83+
84+
@Override
85+
public Player getPlayer() {
86+
return this.playerContext.player;
87+
}
88+
89+
public PlayerContext getContext() {
90+
return this.playerContext;
91+
}
92+
93+
@Override
94+
public Window getWindow() {
95+
return this.window;
96+
}
97+
98+
@Override
99+
public NewTab getNewTab() {
100+
return this.newTab;
101+
}
102+
103+
@Override
104+
public void update() {
105+
this.isUpdating = true;
106+
this.playerContext.player.sendMessage(this.window.draw(this.playerContext));
107+
this.isUpdating = false;
108+
}
109+
110+
@Override
111+
public boolean handleIncoming(Text message) {
112+
try {
113+
this.window.getActiveTab().onTextEntered(this, message);
114+
// Only allow normal chat to get processed if on the global tab
115+
return this.window.getActiveTab() != this.globalTab;
116+
} catch (Exception e) {
117+
e.printStackTrace();
118+
return true; // Just ignore the input
119+
}
120+
}
121+
122+
@Override
123+
public Optional<Text> transformOutgoing(CommandSource sender, Text originalOutgoing, ChatType type) {
124+
if (this.isUpdating) {
125+
// Send it straight out
126+
return Optional.of(originalOutgoing);
127+
}
128+
this.globalTab.appendMessage(originalOutgoing);
129+
return Optional.of(this.window.draw(this.playerContext));
130+
}
131+
132+
@Override
133+
public boolean handleCommand(String[] args) {
134+
String cmd = args[0];
135+
if (cmd.equals("settab")) {
136+
this.window.setTab(Integer.parseInt(args[1]));
137+
} else if (cmd.equals("closetab")) {
138+
this.window.removeTab(Integer.parseInt(args[1]));
139+
} else if (cmd.equals("newtab")) {
140+
this.window.addTab(this.newTab, true);
141+
} else if (cmd.equals("tf") && this.window.getActiveTab() instanceof TextFileTab) {
142+
// TextFileTab specific behaviour, see TextFileTab#clickAction
143+
((TextFileTab) this.window.getActiveTab()).onCommand(this, Integer.parseInt(args[1]), Integer.parseInt(args[2]));
144+
} else {
145+
return false;
146+
}
147+
update();
148+
return true;
149+
}
150+
151+
public void onConfigChange(ConfigurationNode node) {
152+
if (node.getKey().equals("displayWidth")) {
153+
this.playerContext = this.playerContext.withWidth(node.getInt());
154+
} else if (node.getKey().equals("displayHeight")) {
155+
this.playerContext = this.playerContext.withHeight(node.getInt());
156+
} else if (node.getKey().equals("forceUnicode")) {
157+
this.playerContext = this.playerContext.withUnicode(node.getBoolean());
158+
} else if (node.getKey().equals("enabled")) {
159+
if (!node.getBoolean()) {
160+
disable();
161+
}
162+
}
163+
}
164+
165+
private void disable() {
166+
// Force clear the screen
167+
this.isUpdating = true;
168+
for (int i = 0; i < this.playerContext.height; i++) {
169+
this.playerContext.player.sendMessage(Text.NEW_LINE);
170+
}
171+
this.isUpdating = false;
172+
ChatUI.instance().initialize(getPlayer());
173+
}
174+
175+
@Override
176+
public String toString() {
177+
return Objects.toStringHelper(this)
178+
.add("player", this.playerContext)
179+
.add("window", this.window)
180+
.toString();
181+
}
182+
183+
}

src/main/java/com/simon816/chatui/ChatUI.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,17 @@ public void onGameReload(GameReloadEvent event) {
111111

112112
@Listener
113113
public void onPlayerJoin(ClientConnectionEvent.Join event) {
114-
Player player = event.getTargetEntity();
114+
initialize(event.getTargetEntity());
115+
}
116+
117+
void initialize(Player player) {
115118
ConfigurationNode playerSettings = Config.playerConfig(player.getUniqueId());
119+
PlayerChatView view;
116120
if (!playerSettings.getNode("enabled").getBoolean()) {
117-
// Does nothing for now
121+
view = new DisabledChatView(player);
122+
} else {
123+
view = new ActivePlayerChatView(player, playerSettings);
118124
}
119-
PlayerChatView view = new PlayerChatView(player, playerSettings);
120125
this.playerViewMap.put(player.getUniqueId(), view);
121126
view.update();
122127
}

src/main/java/com/simon816/chatui/ChatUICommand.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,8 @@ public CommandResult process(CommandSource source, String arguments) throws Comm
3131
throw new CommandNotFoundException(arguments);
3232
}
3333

34-
// Forward-compatible API 5
35-
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
36-
return getSuggestions(source, arguments);
37-
}
38-
3934
@Override
40-
public List<String> getSuggestions(CommandSource source, String arguments) throws CommandException {
35+
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
4136
return Collections.emptyList();
4237
}
4338

src/main/java/com/simon816/chatui/Config.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,28 @@
99
import java.io.IOException;
1010
import java.util.Collections;
1111
import java.util.Map;
12+
import java.util.Map.Entry;
1213
import java.util.UUID;
1314

1415
public class Config {
1516

17+
public static final int DEFAULT_BUFFER_HEIGHT = 20;
18+
public static final int DEFAULT_BUFFER_WIDTH = 320;
19+
1620
private static ConfigurationLoader<CommentedConfigurationNode> confLoader;
1721

1822
private static Logger logger;
1923
private static CommentedConfigurationNode config;
2024

25+
private static final Map<String, Object> DEFAULTS;
26+
static {
27+
DEFAULTS = Maps.newHashMap();
28+
DEFAULTS.put("enabled", true);
29+
DEFAULTS.put("displayWidth", DEFAULT_BUFFER_WIDTH);
30+
DEFAULTS.put("displayHeight", DEFAULT_BUFFER_HEIGHT);
31+
DEFAULTS.put("forceUnicode", false);
32+
}
33+
2134
public static void init(ConfigurationLoader<CommentedConfigurationNode> confLoader, Logger logger) {
2235
Config.confLoader = confLoader;
2336
Config.logger = logger;
@@ -27,11 +40,14 @@ public static void init(ConfigurationLoader<CommentedConfigurationNode> confLoad
2740
public static ConfigurationNode playerConfig(UUID uuid) {
2841
CommentedConfigurationNode settings = config.getNode("playerSettings", uuid);
2942
if (settings.isVirtual()) {
30-
Map<String, Object> defaults = Maps.newHashMap();
31-
defaults.put("enabled", true);
32-
defaults.put("displayWidth", PlayerChatView.DEFAULT_BUFFER_WIDTH);
33-
defaults.put("displayHeight", PlayerChatView.DEFAULT_BUFFER_HEIGHT);
34-
settings.setValue(defaults);
43+
settings.setValue(DEFAULTS);
44+
} else {
45+
for (Entry<String, Object> e : DEFAULTS.entrySet()) {
46+
CommentedConfigurationNode n = settings.getNode(e.getKey());
47+
if (n.isVirtual()) {
48+
n.setValue(e.getValue());
49+
}
50+
}
3551
}
3652
return settings;
3753
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.simon816.chatui;
2+
3+
import com.simon816.chatui.tabs.NewTab;
4+
import org.spongepowered.api.command.CommandSource;
5+
import org.spongepowered.api.entity.living.player.Player;
6+
import org.spongepowered.api.text.Text;
7+
import org.spongepowered.api.text.chat.ChatType;
8+
import org.spongepowered.api.text.format.TextColors;
9+
10+
import java.util.Optional;
11+
12+
public class DisabledChatView implements PlayerChatView {
13+
14+
private static final Text DISABLED_MESSAGE;
15+
static {
16+
Text.Builder builder = Text.builder("ChatUI is disabled, type ");
17+
builder.append(Text.builder("/chatui enable")
18+
.color(TextColors.GREEN)
19+
.onClick(ChatUI.command("enable"))
20+
.build(), Text.of(" to re-enable"));
21+
DISABLED_MESSAGE = builder.build();
22+
}
23+
private final Player player;
24+
private final PlayerList stubPlayerList;
25+
private final Window stubWindow;
26+
private final NewTab stubNewTab;
27+
28+
public DisabledChatView(Player player) {
29+
this.player = player;
30+
this.stubPlayerList = new PlayerList(player);
31+
this.stubWindow = new Window();
32+
this.stubNewTab = new NewTab();
33+
player.sendMessage(DISABLED_MESSAGE);
34+
}
35+
36+
@Override
37+
public PlayerList getPlayerList() {
38+
return this.stubPlayerList;
39+
}
40+
41+
@Override
42+
public Player getPlayer() {
43+
return this.player;
44+
}
45+
46+
@Override
47+
public Window getWindow() {
48+
return this.stubWindow;
49+
}
50+
51+
@Override
52+
public NewTab getNewTab() {
53+
return this.stubNewTab;
54+
}
55+
56+
@Override
57+
public void update() {
58+
}
59+
60+
@Override
61+
public boolean handleIncoming(Text message) {
62+
return false;
63+
}
64+
65+
@Override
66+
public Optional<Text> transformOutgoing(CommandSource sender, Text originalOutgoing, ChatType type) {
67+
return Optional.of(originalOutgoing);
68+
}
69+
70+
@Override
71+
public boolean handleCommand(String[] args) {
72+
if (args[0].equals("enable")) {
73+
Config.playerConfig(this.player.getUniqueId()).getNode("enabled").setValue(true);
74+
Config.saveConfig();
75+
ChatUI.instance().initialize(this.player);
76+
return true;
77+
}
78+
return false;
79+
}
80+
81+
}

0 commit comments

Comments
 (0)