
com.github.ocraft.s2client.protocol.response.ResponseGameInfo Maven / Gradle / Ivy
The newest version!
package com.github.ocraft.s2client.protocol.response;
/*-
* #%L
* ocraft-s2client-protocol
* %%
* Copyright (C) 2017 - 2018 Ocraft Project
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
import SC2APIProtocol.Sc2Api;
import com.github.ocraft.s2client.protocol.Strings;
import com.github.ocraft.s2client.protocol.game.GameStatus;
import com.github.ocraft.s2client.protocol.game.InterfaceOptions;
import com.github.ocraft.s2client.protocol.game.LocalMap;
import com.github.ocraft.s2client.protocol.game.PlayerInfo;
import com.github.ocraft.s2client.protocol.game.raw.StartRaw;
import com.github.ocraft.s2client.protocol.spatial.Point2d;
import com.github.ocraft.s2client.protocol.spatial.PointI;
import java.nio.file.Paths;
import java.util.*;
import static com.github.ocraft.s2client.protocol.Constants.nothing;
import static com.github.ocraft.s2client.protocol.DataExtractor.tryGet;
import static com.github.ocraft.s2client.protocol.Errors.required;
import static com.github.ocraft.s2client.protocol.Preconditions.isSet;
import static com.github.ocraft.s2client.protocol.Preconditions.requireNotEmpty;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toSet;
public final class ResponseGameInfo extends Response {
private static final long serialVersionUID = -137398200343824705L;
private final String mapName;
private final Set modNames;
private final LocalMap localMap;
private final Set playersInfo;
private final StartRaw startRaw; // Populated if Raw interface is enabled.
private final InterfaceOptions interfaceOptions;
private ResponseGameInfo(Sc2Api.ResponseGameInfo sc2ApiResponseGameInfo, Sc2Api.Status status, int id) {
super(ResponseType.GAME_INFO, GameStatus.from(status), id);
mapName = tryGet(Sc2Api.ResponseGameInfo::getMapName, Sc2Api.ResponseGameInfo::hasMapName)
.apply(sc2ApiResponseGameInfo).orElseThrow(required("map name"));
modNames = new HashSet<>(sc2ApiResponseGameInfo.getModNamesList());
localMap = tryGet(Sc2Api.ResponseGameInfo::getLocalMapPath, Sc2Api.ResponseGameInfo::hasLocalMapPath)
.apply(sc2ApiResponseGameInfo).map(Paths::get).map(LocalMap::of).orElse(nothing());
playersInfo = sc2ApiResponseGameInfo.getPlayerInfoList().stream().map(PlayerInfo::from)
.collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
requireNotEmpty("players info", playersInfo);
startRaw = tryGet(Sc2Api.ResponseGameInfo::getStartRaw, Sc2Api.ResponseGameInfo::hasStartRaw)
.apply(sc2ApiResponseGameInfo).map(StartRaw::from).orElse(nothing());
interfaceOptions = tryGet(Sc2Api.ResponseGameInfo::getOptions, Sc2Api.ResponseGameInfo::hasOptions)
.apply(sc2ApiResponseGameInfo).map(InterfaceOptions::from).orElseThrow(required("interface options"));
}
public static ResponseGameInfo from(Sc2Api.Response sc2ApiResponse) {
if (!hasGameInfoResponse(sc2ApiResponse)) {
throw new IllegalArgumentException("provided argument doesn't have game info response");
}
return new ResponseGameInfo(sc2ApiResponse.getGameInfo(), sc2ApiResponse.getStatus(), sc2ApiResponse.getId());
}
private static boolean hasGameInfoResponse(Sc2Api.Response sc2ApiResponse) {
return isSet(sc2ApiResponse) && sc2ApiResponse.hasGameInfo();
}
public String getMapName() {
return mapName;
}
public Set getModNames() {
return modNames;
}
public Optional getLocalMap() {
return Optional.ofNullable(localMap);
}
public Set getPlayersInfo() {
return playersInfo;
}
public Optional getStartRaw() {
return Optional.ofNullable(startRaw);
}
public InterfaceOptions getInterfaceOptions() {
return interfaceOptions;
}
public PointI convertWorldToMinimap(Point2d world) {
return getInterfaceOptions()
.getFeatureLayer()
.filter(spatialCameraSetup -> getStartRaw().isPresent())
.map(spatialCameraSetup -> {
int imageWidth = spatialCameraSetup.getMinimap().getX();
int imageHeight = spatialCameraSetup.getMinimap().getY();
float mapWidth = (float) getStartRaw().get().getMapSize().getX();
float mapHeight = (float) getStartRaw().get().getMapSize().getY();
// Pixels always cover a square amount of world space. The scale is determined
// by the largest axis of the map.
float pixelSize = Math.max(mapWidth / imageWidth, mapHeight / imageHeight);
// Origin of world space is bottom left. Origin of image space is top left.
// Upper left corner of the map corresponds to the upper left corner of the upper
// left pixel of the feature layer.
float imageOriginX = 0;
float imageOriginY = mapHeight;
float imageRelativeX = world.getX() - imageOriginX;
float imageRelativeY = imageOriginY - world.getY();
int imageX = (int) (imageRelativeX / pixelSize);
int imageY = (int) (imageRelativeY / pixelSize);
return PointI.of(imageX, imageY);
}).orElseThrow(() -> new IllegalStateException("Feature layer interface is required."));
}
public PointI convertWorldToCamera(Point2d cameraWorld, Point2d world) {
return getInterfaceOptions()
.getFeatureLayer()
.filter(spatialCameraSetup -> getStartRaw().isPresent())
.filter(spatialCameraSetup -> spatialCameraSetup.getWidth().isPresent())
.map(spatialCameraSetup -> {
float cameraSize = spatialCameraSetup.getWidth().get();
int imageWidth = spatialCameraSetup.getMap().getX();
int imageHeight = spatialCameraSetup.getMap().getY();
// Pixels always cover a square amount of world space. The scale is determined
// by making the shortest axis of the camera match the requested cameraSize.
float pixelSize = cameraSize / Math.min(imageWidth, imageHeight);
float imageWidthWorld = pixelSize * imageWidth;
float imageHeightWorld = pixelSize * imageHeight;
// Origin of world space is bottom left. Origin of image space is top left.
// The feature layer is centered around the camera target position.
float imageOriginX = cameraWorld.getX() - imageWidthWorld / 2.0f;
float imageOriginY = cameraWorld.getY() + imageHeightWorld / 2.0f;
float imageRelativeX = world.getX() - imageOriginX;
float imageRelativeY = imageOriginY - world.getY();
int imageX = (int) (imageRelativeX / pixelSize);
int imageY = (int) (imageRelativeY / pixelSize);
return PointI.of(imageX, imageY);
}).orElseThrow(() -> new IllegalStateException("Feature layer interface is required."));
}
public Point2d findRandomLocation() {
return getStartRaw().map(start -> {
PointI playableMin = start.getPlayableArea().getP0();
PointI playableMax = start.getPlayableArea().getP1();
return findRandomLocation(playableMin.toPoint2d(), playableMax.toPoint2d());
}).orElseGet(() -> Point2d.of(0.0f, 0.0f));
}
public Point2d findRandomLocation(Point2d min, Point2d max) {
return Point2d.of(
(float) ((max.getX() - min.getX()) * Math.random() + min.getX()),
(float) ((max.getY() - min.getY()) * Math.random() + min.getY()));
}
public PointI findCenterOfMap() {
return getStartRaw().map(start -> start.getPlayableArea().getP1().div(2)).orElseGet(() -> PointI.of(0, 0));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ResponseGameInfo)) return false;
if (!super.equals(o)) return false;
ResponseGameInfo that = (ResponseGameInfo) o;
return that.canEqual(this) &&
mapName.equals(that.mapName) &&
modNames.equals(that.modNames) &&
(Objects.equals(localMap, that.localMap)) &&
playersInfo.equals(that.playersInfo) &&
(Objects.equals(startRaw, that.startRaw)) &&
interfaceOptions.equals(that.interfaceOptions);
}
@Override
public boolean canEqual(Object other) {
return other instanceof ResponseGameInfo;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + mapName.hashCode();
result = 31 * result + modNames.hashCode();
result = 31 * result + (localMap != null ? localMap.hashCode() : 0);
result = 31 * result + playersInfo.hashCode();
result = 31 * result + (startRaw != null ? startRaw.hashCode() : 0);
result = 31 * result + interfaceOptions.hashCode();
return result;
}
@Override
public String toString() {
return Strings.toJson(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy