All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.llbit.chunky.ui.render.EntitiesTab Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2016 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky 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.
 *
 * Chunky 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 Chunky.  If not, see .
 */
package se.llbit.chunky.ui.render;

import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Tab;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.stage.FileChooser;
import se.llbit.chunky.renderer.scene.PlayerModel;
import se.llbit.chunky.renderer.scene.Scene;
import se.llbit.chunky.ui.DoubleAdjuster;
import se.llbit.chunky.ui.RenderControlsFxController;
import se.llbit.chunky.world.entity.Entity;
import se.llbit.chunky.world.entity.PlayerEntity;
import se.llbit.json.JsonObject;
import se.llbit.log.Log;
import se.llbit.math.QuickMath;
import se.llbit.math.Vector3;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.function.Consumer;

public class EntitiesTab extends Tab implements RenderControlsTab, Initializable {
  private Scene scene;

  static class PlayerData {
    public final PlayerEntity entity;
    public final String name;

    public PlayerData(PlayerEntity entity, Scene scene) {
      this.entity = entity;

      JsonObject profile = scene.getPlayerProfile(entity);
      name = getName(profile);
    }

    private static String getName(JsonObject profile) {
      return profile.get("name").stringValue("Unknown");
    }

    @Override public String toString() {
      return entity.uuid;
    }

    @Override public int hashCode() {
      return entity.uuid.hashCode();
    }

    @Override public boolean equals(Object obj) {
      if (obj instanceof PlayerData) {
        return ((PlayerData) obj).entity.uuid.equals(entity.uuid);
      }
      return false;
    }
  }

  @FXML private TableView entityTable;
  @FXML private TableColumn nameCol;
  @FXML private TableColumn idCol;
  @FXML private Button delete;
  @FXML private Button add;
  @FXML private Button cameraToPlayer;
  @FXML private Button playerToCamera;
  @FXML private Button playerToTarget;
  @FXML private Button faceCamera;
  @FXML private Button faceTarget;
  @FXML private ChoiceBox playerModel;
  @FXML private TextField skin;
  @FXML private Button selectSkin;
  @FXML private DoubleAdjuster direction;
  @FXML private DoubleAdjuster headYaw;
  @FXML private DoubleAdjuster headPitch;
  @FXML private DoubleAdjuster leftArmPose;
  @FXML private DoubleAdjuster rightArmPose;
  @FXML private DoubleAdjuster leftLegPose;
  @FXML private DoubleAdjuster rightLegPose;

  public EntitiesTab() throws IOException {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("EntitiesTab.fxml"));
    loader.setRoot(this);
    loader.setController(this);
    loader.load();
  }

  @Override public void update(Scene scene) {
    Collection missing = new HashSet<>(entityTable.getItems());
    for (Entity entity : scene.getActors()) {
      if (entity instanceof PlayerEntity) {
        PlayerData data = new PlayerData((PlayerEntity) entity, scene);
        if (!entityTable.getItems().contains(data)) {
          entityTable.getItems().add(data);
        }
        missing.remove(data);
      }
    }
    entityTable.getItems().removeAll(missing);
  }

  @Override public Tab getTab() {
    return this;
  }

  private void updatePlayer(PlayerEntity player) {
    playerModel.getSelectionModel().select(player.model);
    skin.setText(player.skin);
    direction.set(player.yaw);
    headYaw.set(player.headYaw);
    headPitch.set(player.pitch);
    leftArmPose.set(player.leftArmPose);
    rightArmPose.set(player.rightArmPose);
    leftLegPose.set(player.leftLegPose);
    rightLegPose.set(player.rightLegPose);
  }

  @Override public void initialize(URL location, ResourceBundle resources) {
    add.setTooltip(new Tooltip("Add a player at the target position."));
    add.setOnAction(e -> {
      Collection entities = scene.getActors();
      Set ids = new HashSet<>();
      for (Entity entity : entities) {
        if (entity instanceof PlayerEntity) {
          ids.add(((PlayerEntity) entity).uuid);
        }
      }
      // Pick a new UUID for the new entity.
      long id = System.currentTimeMillis();
      while (ids.contains(String.format("%016X%016X", 0, id))) {
        id += 1;
      }
      Vector3 position = scene.getTargetPosition();
      if (position == null) {
        position = new Vector3(scene.camera().getPosition());
      }
      PlayerEntity player = new PlayerEntity(String.format("%016X%016X", 0, id), position, 0, 0);
      withSelected(selected -> {
        player.skin = selected.skin;
        player.model = selected.model;
      });
      player.randomPoseAndLook();
      scene.addPlayer(player);
      PlayerData data = new PlayerData(player, scene);
      entityTable.getItems().add(data);
      entityTable.getSelectionModel().select(data);
    });
    delete.setTooltip(new Tooltip("Delete the selected player."));
    delete.setOnAction(e -> withSelected(selected -> {
      scene.removePlayer(selected);
      update(scene);
    }));
    selectSkin.setOnAction(e -> withSelected(player -> {
      FileChooser fileChooser = new FileChooser();
      fileChooser.setTitle("Load Skin");
      fileChooser
          .setSelectedExtensionFilter(new FileChooser.ExtensionFilter("Minecraft skin", "*.png"));
      File skinFile = fileChooser.showOpenDialog(getTabPane().getScene().getWindow());
      if (skinFile != null) {
        player.setTexture(skinFile.getAbsolutePath());
        skin.setText(skinFile.getAbsolutePath());
        scene.rebuildActorBvh();
      }
    }));
    entityTable.setRowFactory(tbl -> {
      TableRow row = new TableRow<>();
      row.setOnMouseClicked(e -> {
        if (e.getClickCount() == 2 && !row.isEmpty()) {
          e.consume();
          try {
            Poser poser = new Poser(row.getItem());
            poser.show();
          } catch (IOException e1) {
            Log.warn("Could not open player poser window.", e1);
          }
        }
      });
      return row;
    });
    cameraToPlayer.setTooltip(new Tooltip("Move the camera to the selected player position."));
    cameraToPlayer.setOnAction(e -> withSelected(player -> scene.camera().moveToPlayer(player)));
    playerToCamera.setTooltip(new Tooltip("Move the selected player to the camera position."));
    playerToCamera.setOnAction(e -> withSelected(player -> {
      player.position.set(scene.camera().getPosition());
      scene.rebuildActorBvh();
    }));
    playerToTarget.setTooltip(new Tooltip("Move the selected player to the current target."));
    playerToTarget.setOnAction(e -> withSelected(player -> {
      Vector3 target = scene.getTargetPosition();
      if (target != null) {
        player.position.set(target);
        scene.rebuildActorBvh();
      }
    }));
    faceCamera.setTooltip(new Tooltip("Makes the selected player look at the camera."));
    faceCamera.setOnAction(e -> withSelected(player -> {
      player.lookAt(scene.camera().getPosition());
      scene.rebuildActorBvh();
    }));
    faceTarget.setTooltip(new Tooltip("Makes the selected player look at the current view target."));
    faceTarget.setOnAction(e -> withSelected(player -> {
      Vector3 target = scene.getTargetPosition();
      if (target != null) {
        player.lookAt(target);
        scene.rebuildActorBvh();
      }
    }));
    entityTable.getSelectionModel().selectedItemProperty()
        .addListener((observable, oldValue, newValue) -> {
          if (newValue != null) {
            updatePlayer(newValue.entity);
          }
        });
    nameCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().name));
    idCol.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().toString()));
    playerModel.getItems().addAll(PlayerModel.values());
    playerModel.getSelectionModel().selectedItemProperty().addListener(
        (observable, oldValue, newValue) -> withSelected(player -> {
          player.model = newValue;
          scene.rebuildActorBvh();
        }));
    direction.setName("Direction");
    direction.setRange(-Math.PI, Math.PI);
    direction.onValueChange(value -> withSelected(player -> {
      player.yaw = value;
      scene.rebuildActorBvh();
    }));
    headYaw.setName("Head yaw");
    headYaw.setRange(-QuickMath.HALF_PI, QuickMath.HALF_PI);
    headYaw.onValueChange(value -> withSelected(player -> {
      player.headYaw = value;
      scene.rebuildActorBvh();
    }));
    headPitch.setName("Head pitch");
    headPitch.setRange(-QuickMath.HALF_PI, QuickMath.HALF_PI);
    headPitch.onValueChange(value -> withSelected(player -> {
      player.pitch = value;
      scene.rebuildActorBvh();
    }));
    leftArmPose.setName("Left arm pose");
    leftArmPose.setRange(-Math.PI, Math.PI);
    leftArmPose.onValueChange(value -> withSelected(player -> {
      player.leftArmPose = value;
      scene.rebuildActorBvh();
    }));
    rightArmPose.setName("Right arm pose");
    rightArmPose.setRange(-Math.PI, Math.PI);
    rightArmPose.onValueChange(value -> withSelected(player -> {
      player.rightArmPose = value;
      scene.rebuildActorBvh();
    }));
    leftLegPose.setName("Left leg pose");
    leftLegPose.setRange(-QuickMath.HALF_PI, QuickMath.HALF_PI);
    leftLegPose.onValueChange(value -> withSelected(player -> {
      player.leftLegPose = value;
      scene.rebuildActorBvh();
    }));
    rightLegPose.setName("Right leg pose");
    rightLegPose.setRange(-QuickMath.HALF_PI, QuickMath.HALF_PI);
    rightLegPose.onValueChange(value -> withSelected(player -> {
      player.rightLegPose = value;
      scene.rebuildActorBvh();
    }));
  }

  private void withSelected(Consumer consumer) {
    PlayerData player = entityTable.getSelectionModel().getSelectedItem();
    if (player != null) {
      consumer.accept(player.entity);
    }
  }

  @Override public void setController(RenderControlsFxController controller) {
    scene = controller.getRenderController().getSceneManager().getScene();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy