/* Copyright (C) 2011 monte This file is part of PSP NetParty. PSP NetParty is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package pspnetparty.client.swt.plugin; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SocketChannel; import org.eclipse.jface.preference.PreferenceNode; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import pspnetparty.client.swt.PlayClient; import pspnetparty.client.swt.config.IPreferenceNodeProvider; import pspnetparty.client.swt.message.Chat; import pspnetparty.client.swt.message.IMessage; import pspnetparty.client.swt.message.IMessageListener; import pspnetparty.client.swt.message.LobbyCircleChat; import pspnetparty.client.swt.message.PrivateChat; import pspnetparty.lib.IniSection; import pspnetparty.lib.Utility; import pspnetparty.lib.constants.AppConstants; public class BouyomiChanPlugin implements IPlugin, IPreferenceNodeProvider { private static final String SECTION_NAME = "BouyomiChan"; private static final String INI_USE = "Use"; private static final String INI_ADDRESS = "Address"; private static final String INI_READ_MY_CHAT = "ReadMyChat"; private static final String INI_READ_ROOM_CHAT = "ReadRoomChat"; private static final String INI_READ_LOBBY_CHAT = "ReadLobbyChat"; private static final String INI_READ_CIRCLE_CHAT = "ReadCircleChat"; private static final String INI_READ_PRIVATE_CHAT = "ReadPrivateChat"; private PlayClient application; private IniSection iniSection; private ByteBuffer headerBuffer; private InetSocketAddress socketAddress; private boolean use; private String address; private boolean readMyChat; private boolean readRoomChat; private boolean readLobbyChat; private boolean readCircleChat; private boolean readPrivateChat; private int errorCount = 0; public BouyomiChanPlugin() { headerBuffer = ByteBuffer.allocate(15); headerBuffer.order(ByteOrder.LITTLE_ENDIAN); headerBuffer.putShort((short) 0); // コマンド headerBuffer.putShort((short) -1); // 速度 headerBuffer.putShort((short) -1); // 音量 // buffer.putShort((short) 0); headerBuffer.putShort((short) 0); // 声質 headerBuffer.put((byte) 0); // 文字コード } public void sendMessage(InetSocketAddress address, String message) { byte[] bytes = message.getBytes(AppConstants.CHARSET); ByteBuffer buffer = ByteBuffer.allocate(bytes.length + 4); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.putInt(bytes.length); buffer.put(bytes); try { SocketChannel channel = SocketChannel.open(); channel.connect(address); headerBuffer.flip(); buffer.flip(); channel.write(new ByteBuffer[] { headerBuffer, buffer }); channel.close(); errorCount = 0; } catch (IOException e) { if (errorCount < 5) { errorCount++; application.getArenaWindow().appendToSystemLog(Utility.stackTraceToString(e), true); e.printStackTrace(); } else { socketAddress = null; use = false; iniSection.set(INI_USE, false); errorCount = 0; application.getArenaWindow().appendToSystemLog("棒読みちゃんに接続できませんでした。設定を見直してください。", true); } } } @Override public void initPlugin(PlayClient application) { this.application = application; iniSection = application.getIniSection(SECTION_NAME); application.addConfigPageProvider(this); use = iniSection.get(INI_USE, false); address = iniSection.get(INI_ADDRESS, ":50001"); readMyChat = iniSection.get(INI_READ_MY_CHAT, false); readRoomChat = iniSection.get(INI_READ_ROOM_CHAT, true); readLobbyChat = iniSection.get(INI_READ_LOBBY_CHAT, true); readCircleChat = iniSection.get(INI_READ_CIRCLE_CHAT, true); readPrivateChat = iniSection.get(INI_READ_PRIVATE_CHAT, true); application.addRoomMessageListener(new IMessageListener() { @Override public void messageReceived(IMessage message) { if (socketAddress == null) return; if (!readRoomChat) return; if (message instanceof Chat) { Chat chat = (Chat) message; if (!chat.isMine() || readMyChat) sendMessage(socketAddress, chat.getMessage()); } } }); application.addLobbyMessageListener(new IMessageListener() { @Override public void messageReceived(IMessage message) { if (socketAddress == null) return; if (message instanceof PrivateChat) { PrivateChat chat = (PrivateChat) message; if (!chat.isMine() && readPrivateChat) sendMessage(socketAddress, chat.getMessage()); } else if (message instanceof LobbyCircleChat) { if (!readCircleChat) return; LobbyCircleChat chat = (LobbyCircleChat) message; if (!chat.isMine() || readMyChat) sendMessage(socketAddress, chat.getMessage()); } else if (message instanceof Chat) { if (!readLobbyChat) return; Chat chat = (Chat) message; if (!chat.isMine() || readMyChat) sendMessage(socketAddress, chat.getMessage()); } } }); setup(); } @Override public void disposePlugin() { } private void setup() { if (use && !Utility.isEmpty(address)) { socketAddress = Utility.parseSocketAddress(address); } else { socketAddress = null; } } @Override public PreferenceNode createPreferenceNode() { return new PreferenceNode("bouyomichan", new BouyomiChanPage()); } private class BouyomiChanPage extends PreferencePage { private Button useCheckButton; private Text addressText; private Button readMyChatCheck; private Button readRoomChatCheck; private Button readLobbyChatCheck; private Button readCircleChatCheck; private Button readPrivateChatCheck; public BouyomiChanPage() { super("棒読みちゃん"); noDefaultAndApplyButton(); } @Override protected Control createContents(Composite parent) { GridLayout gridLayout; Composite container = new Composite(parent, SWT.NONE); gridLayout = new GridLayout(2, false); gridLayout.horizontalSpacing = 6; gridLayout.verticalSpacing = 6; gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; gridLayout.marginTop = 2; container.setLayout(gridLayout); useCheckButton = new Button(container, SWT.CHECK | SWT.FLAT); useCheckButton.setText("棒読みちゃんを使用する ※棒読みちゃん(フリーソフト)が別途必要になります"); useCheckButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); useCheckButton.setSelection(use); Label addressLabel = new Label(container, SWT.NONE); addressLabel.setText("アドレス"); addressLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); addressText = new Text(container, SWT.BORDER | SWT.SINGLE); addressText.setTextLimit(100); addressText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); addressText.setText(address); addressText.setEnabled(use); readMyChatCheck = new Button(container, SWT.CHECK | SWT.FLAT); readMyChatCheck.setText("自分のチャットを読み上げる"); readMyChatCheck.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false, 2, 1)); readMyChatCheck.setSelection(readMyChat); readRoomChatCheck = new Button(container, SWT.CHECK | SWT.FLAT); readRoomChatCheck.setText("プレイルームのチャットを読み上げる"); readRoomChatCheck.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false, 2, 1)); readRoomChatCheck.setSelection(readRoomChat); readLobbyChatCheck = new Button(container, SWT.CHECK | SWT.FLAT); readLobbyChatCheck.setText("ロビー全体のチャットを読み上げる"); readLobbyChatCheck.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false, 2, 1)); readLobbyChatCheck.setSelection(readLobbyChat); readCircleChatCheck = new Button(container, SWT.CHECK | SWT.FLAT); readCircleChatCheck.setText("サークルのチャットを読み上げる"); readCircleChatCheck.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false, 2, 1)); readCircleChatCheck.setSelection(readCircleChat); readPrivateChatCheck = new Button(container, SWT.CHECK | SWT.FLAT); readPrivateChatCheck.setText("プライベートメッセージを読み上げる"); readPrivateChatCheck.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false, 2, 1)); readPrivateChatCheck.setSelection(readPrivateChat); useCheckButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { if (useCheckButton.getSelection()) { addressText.setEnabled(true); } else { addressText.setEnabled(false); } } }); return container; } private void reflectValues() { if (!isControlCreated()) return; use = useCheckButton.getSelection(); iniSection.set(INI_USE, use); address = addressText.getText(); iniSection.set(INI_ADDRESS, address); setup(); readMyChat = readMyChatCheck.getSelection(); iniSection.set(INI_READ_MY_CHAT, readMyChat); readRoomChat = readRoomChatCheck.getSelection(); iniSection.set(INI_READ_ROOM_CHAT, readRoomChat); readLobbyChat = readLobbyChatCheck.getSelection(); iniSection.set(INI_READ_LOBBY_CHAT, readLobbyChat); readCircleChat = readCircleChatCheck.getSelection(); iniSection.set(INI_READ_CIRCLE_CHAT, readCircleChat); readPrivateChat = readPrivateChatCheck.getSelection(); iniSection.set(INI_READ_PRIVATE_CHAT, readPrivateChat); } @Override public boolean performOk() { reflectValues(); return super.performOk(); } } public static void main(String[] args) throws Exception { String message = "棒読みちゃんてすと"; InetSocketAddress address = new InetSocketAddress(50001); BouyomiChanPlugin bc = new BouyomiChanPlugin(); bc.sendMessage(address, message); bc.sendMessage(address, message); } }