2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.minecraft.internal.handler;
15 import org.openhab.binding.minecraft.internal.MinecraftBindingConstants;
16 import org.openhab.binding.minecraft.internal.config.PlayerConfig;
17 import org.openhab.binding.minecraft.internal.message.OHMessage;
18 import org.openhab.binding.minecraft.internal.message.data.PlayerData;
19 import org.openhab.binding.minecraft.internal.message.data.commands.PlayerCommandData;
20 import org.openhab.core.library.types.DecimalType;
21 import org.openhab.core.library.types.OnOffType;
22 import org.openhab.core.library.types.PointType;
23 import org.openhab.core.library.types.StringType;
24 import org.openhab.core.thing.Bridge;
25 import org.openhab.core.thing.ChannelUID;
26 import org.openhab.core.thing.Thing;
27 import org.openhab.core.thing.ThingStatus;
28 import org.openhab.core.thing.ThingStatusDetail;
29 import org.openhab.core.thing.binding.BaseThingHandler;
30 import org.openhab.core.thing.binding.ThingHandler;
31 import org.openhab.core.types.Command;
32 import org.openhab.core.types.State;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 import com.google.gson.Gson;
37 import com.google.gson.GsonBuilder;
38 import com.google.gson.JsonElement;
41 import rx.Subscription;
44 * The {@link MinecraftPlayerHandler} is responsible for handling commands, which are
45 * sent to one of the channels.
47 * @author Mattias Markehed - Initial contribution
49 public class MinecraftPlayerHandler extends BaseThingHandler {
51 private Logger logger = LoggerFactory.getLogger(MinecraftPlayerHandler.class);
53 private Subscription playerSubscription;
54 private MinecraftServerHandler bridgeHandler;
55 private PlayerConfig config;
56 private Gson gson = new GsonBuilder().create();
58 public MinecraftPlayerHandler(Thing thing) {
63 public void initialize() {
64 this.bridgeHandler = getBridgeHandler();
65 this.config = getThing().getConfiguration().as(PlayerConfig.class);
67 if (bridgeHandler == null || getThing().getBridgeUID() == null) {
68 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge configured");
73 updateStatus(ThingStatus.ONLINE);
74 hookupListeners(bridgeHandler);
78 public void dispose() {
80 if (!playerSubscription.isUnsubscribed()) {
81 playerSubscription.unsubscribe();
85 private void hookupListeners(MinecraftServerHandler bridgeHandler) {
86 playerSubscription = bridgeHandler.getPlayerRx().doOnNext(players -> {
87 boolean playerOnline = false;
88 for (PlayerData player : players) {
89 if (config.getName().equals(player.getName())) {
94 State onlineState = OnOffType.from(playerOnline);
95 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_ONLINE, onlineState);
96 }).flatMap(players -> Observable.from(players)).filter(player -> config.getName().equals(player.getName()))
97 .subscribe(player -> updatePlayerState(player));
101 * Updates the state of player
103 * @param player the player to update
105 private void updatePlayerState(PlayerData player) {
106 State playerLevel = new DecimalType(player.getLevel());
107 State playerLevelPercentage = new DecimalType(player.getExperience());
108 State playerTotalExperience = new DecimalType(player.getTotalExperience());
109 State playerHealth = new DecimalType(player.getHealth());
110 State playerWalkSpeed = new DecimalType(player.getWalkSpeed());
111 DecimalType longitude = new DecimalType(player.getLocation().getX());
112 DecimalType latitude = new DecimalType(player.getLocation().getY());
113 DecimalType altitude = new DecimalType(player.getLocation().getY());
114 State playerLocation = new PointType(latitude, longitude, altitude);
115 State playerGameMode = new StringType(player.getGameMode());
117 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_LEVEL_PERCENTAGE, playerLevelPercentage);
118 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_TOTAL_EXPERIENCE, playerTotalExperience);
119 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_LEVEL, playerLevel);
120 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_HEALTH, playerHealth);
121 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_WALK_SPEED, playerWalkSpeed);
122 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_LOCATION, playerLocation);
123 updateState(MinecraftBindingConstants.CHANNEL_PLAYER_GAME_MODE, playerGameMode);
126 private String getPlayerName() {
127 return config.getName();
130 private synchronized MinecraftServerHandler getBridgeHandler() {
131 Bridge bridge = getBridge();
132 if (bridge == null) {
133 logger.debug("Required bridge not defined for device {}.", getThing().getUID());
136 return getBridgeHandler(bridge);
140 private synchronized MinecraftServerHandler getBridgeHandler(Bridge bridge) {
141 MinecraftServerHandler bridgeHandler = null;
143 ThingHandler handler = bridge.getHandler();
144 if (handler instanceof MinecraftServerHandler serverHandler) {
145 bridgeHandler = serverHandler;
147 logger.debug("No available bridge handler found yet. Bridge: {} .", bridge.getUID());
148 bridgeHandler = null;
150 return bridgeHandler;
154 public void updateState(String channelID, State state) {
155 ChannelUID channelUID = new ChannelUID(this.getThing().getUID(), channelID);
156 updateState(channelUID, state);
160 * Send a player command to server.
162 * @param type the type of command to send
163 * @param playerName the name of the player to target
164 * @param value the related to command
166 private void sendPlayerCommand(String type, String playerName, String value) {
167 PlayerCommandData playerCommand = new PlayerCommandData(type, playerName, value);
168 JsonElement serializedCommand = gson.toJsonTree(playerCommand);
169 logger.debug("Command: {}", serializedCommand);
170 bridgeHandler.sendMessage(new OHMessage(OHMessage.MESSAGE_TYPE_PLAYER_COMMANDS, serializedCommand));
174 public void handleCommand(ChannelUID channelUID, Command command) {
175 switch (channelUID.getId()) {
176 case MinecraftBindingConstants.CHANNEL_PLAYER_HEALTH:
177 sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_HEALTH, getPlayerName(), command.toString());
179 case MinecraftBindingConstants.CHANNEL_PLAYER_LEVEL:
180 sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_LEVEL, getPlayerName(), command.toString());
182 case MinecraftBindingConstants.CHANNEL_PLAYER_WALK_SPEED:
183 sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_WALK_SPEED, getPlayerName(), command.toString());
185 case MinecraftBindingConstants.CHANNEL_PLAYER_GAME_MODE:
186 sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_GAME_MODE, getPlayerName(), command.toString());
188 case MinecraftBindingConstants.CHANNEL_PLAYER_LOCATION:
189 sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_LOCATION, getPlayerName(), command.toString());