package com.fdkk.fdkkmeta.grpcService; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.fdkk.fdkkmeta.config.MetaConfig; import com.fdkk.fdkkmeta.domain.dto.RouteDto; import com.fdkk.fdkkmeta.domain.entity.mysql.BreakpointsEntity; import com.fdkk.fdkkmeta.domain.entity.mysql.RotateFrameEntity; import com.fdkk.fdkkmeta.domain.entity.mysql.MoveFrameEntity; import com.fdkk.fdkkmeta.domain.entity.mysql.UserEntity; import com.fdkk.fdkkmeta.domain.po.AnglePO; import com.fdkk.fdkkmeta.domain.po.PointPO; import com.fdkk.fdkkmeta.grpc.*; import com.fdkk.fdkkmeta.redis.RedisCache; import com.fdkk.fdkkmeta.service.BreakpointsService; import com.fdkk.fdkkmeta.service.MoveFrameService; import com.fdkk.fdkkmeta.service.RotateFrameService; import com.fdkk.fdkkmeta.service.UserService; import com.fdkk.fdkkmeta.util.ProtoJsonUtils; import com.fdkk.fdkkmeta.util.kesar.GetRoute; import com.google.protobuf.Message; import com.googlecode.protobuf.format.JsonFormat; import io.grpc.stub.StreamObserver; import lombok.extern.slf4j.Slf4j; import net.devh.boot.grpc.server.service.GrpcService; import org.springframework.beans.factory.annotation.Autowired; import java.io.File; import java.io.IOException; import java.util.List; /** * @author Xiewj * @date 2022/5/9 */ @GrpcService @Slf4j public class sceneGrpcServer extends SceneGrpcServiceGrpc.SceneGrpcServiceImplBase { @Autowired MetaConfig metaConfig; @Autowired UserService userService; @Autowired BreakpointsService breakpointsService; @Autowired RotateFrameService rotateFrameService; @Autowired MoveFrameService moveFrameService; @Autowired RedisCache redisCache; /*** * 回复 案例 * SceneReply res = SceneReply.newBuilder().setRes(id+","+name).build(); * responseObserver.onNext(res); */ /* @Override public void testMethod(SceneRequest request, StreamObserver responseObserver) { // grpc服务端获取调用端请求参数 String id = request.getId(); String name = request.getName(); // 这里可以有自己的业务代码,只需要按照porto中的返回类型返回参数即可 SceneReply res = SceneReply.newBuilder().setRes(id+","+name).build(); responseObserver.onNext(res); responseObserver.onCompleted(); log.info("回复{}",res); } */ @Override public void getRoute(RouteRequest request, StreamObserver responseObserver) { // grpc服务端获取调用端请求参数 String sceneCode = request.getSceneCode(); Point sLocation = request.getSLocation(); Point eLocation = request.getELocation(); RouteDto po=new RouteDto(); PointPO s=new PointPO(); s.setX(Double.parseDouble(sLocation.getX())); s.setY(Double.parseDouble(sLocation.getY())); s.setZ(Double.parseDouble(sLocation.getY())); PointPO e=new PointPO(); e.setX(Double.parseDouble(eLocation.getX())); e.setY(Double.parseDouble(eLocation.getY())); e.setZ(Double.parseDouble(eLocation.getY())); po.setE_location(e); po.setS_location(s); po.setSceneCode(sceneCode); JSONArray maps = GetRoute.getRoute(metaConfig.getFreespacePath()+ File.separator +"target_freespace.json", po); // 这里可以有自己的业务代码,只需要按照porto中的返回类型返回参数即可 RouteReply.Builder builder = RouteReply.newBuilder(); if (ArrayUtil.isNotEmpty(maps)) { for (int i = 0; i < maps.size(); i++) { RouteArray.Builder addInBuilder = builder.addInBuilder(); ProtoJsonUtils.toProtoBean(addInBuilder, maps.get(i).toString()); } } responseObserver.onNext(builder.build()); responseObserver.onCompleted(); } @Override public void init(InitRequest request, StreamObserver responseObserver) { try { String user_id = request.getUserId(); String nick_name = request.getNickName(); String skin_id = request.getSkinId(); String avatar_id = request.getAvatarId(); String room_id = request.getRoomId(); String app_id = request.getAppId(); //保存user UserEntity userEntity=new UserEntity(); userEntity.setAppId(app_id); userEntity.setAvatarId(avatar_id); userEntity.setNickName(nick_name); userEntity.setRoomId(room_id); userEntity.setSkinId(skin_id); userEntity.setFrameId(0L); userEntity.setBreakPointId(0L); //初始化的时候可以写死 AnglePO player_angle = new AnglePO(); player_angle.setPitch(0); player_angle.setYaw(0); player_angle.setRoll(0); userEntity.setPlayerAngle(player_angle); userService.save(userEntity); } catch(Exception e) { e.printStackTrace(); } } @Override public void rotate(RotateRequest request, StreamObserver responseObserver) { try { /* { "action_type":1014, "rotation_action": { "vertical_move":0, "horizontal_move":-0.020630372492836675 }, "trace_id":"b40a894e-cd59-4db5-8d75-a8466a0c9f15", "user_id":"0a3987974feb4" } */ int action_type = request.getActionType(); String trace_id = request.getTraceId(); String user_id = request.getUserId(); RotationAction rotation_action = request.getRotationAction(); double horizontal_move = rotation_action.getHorizontalMove(); //这三个变量从user表和rotateframe表里取 UserEntity user = userService.findUserId(user_id); Long breakPointId = user.getBreakPointId(); BreakpointsEntity breakpointsEntity = breakpointsService.findByAppIdAndBreakPointId(user.getAppId(),breakPointId); RotateFrameEntity rotateFrameEntity = rotateFrameService.findById(user.getFrameId()); PointPO playerPoint = breakpointsEntity.getPosition(); Point playerPosition = createPoint(String.valueOf(playerPoint.getX()),String.valueOf(playerPoint.getY()),String.valueOf(playerPoint.getZ())); AnglePO playerAnglePO = user.getPlayerAngle(); AngleUe4 playerAngle = createAngle(playerAnglePO.getPitch(),playerAnglePO.getYaw(),playerAnglePO.getRoll()); Space player = createSpace(playerPosition,playerAngle); double hAngle = horizontal_move * 90; int offFrameIndex = (int)Math.ceil(hAngle); int currentFrame = rotateFrameEntity.getFrameIndex(); //从数据库里读取 currentFrame +=offFrameIndex; if(currentFrame<0){ currentFrame+=360; } else{ currentFrame = currentFrame % 359; } //currentFrame log.info("currentFrame{}",currentFrame); String appId = user.getAppId(); rotateFrameEntity = rotateFrameService.findByAppIdAndBreakPointIdAndFrameIndex(appId,breakPointId,currentFrame); PointPO cameraPoint = rotateFrameEntity.getCameraPosition(); Point cameraPosition = createPoint(String.valueOf(cameraPoint.getX()),String.valueOf(cameraPoint.getY()),String.valueOf(cameraPoint.getZ())); AnglePO cameraAnglePO = rotateFrameEntity.getCameraAngle(); AngleUe4 cameraAngle = createAngle(cameraAnglePO.getPitch(),cameraAnglePO.getYaw(),cameraAnglePO.getRoll()); Space camera = createSpace(cameraPosition,cameraAngle); //对准player Point cameraCenter = createPoint(String.valueOf(playerPoint.getX()),String.valueOf(playerPoint.getY()),String.valueOf(playerPoint.getZ())); State playerState = createPlayerState( player, camera, cameraCenter); RenderInfo renderInfo = createRenderInfo(); Event event = createEvent(); UserState userState = createUserState( user_id, playerState, renderInfo, event); String frameSrc = metaConfig.getVideoFramePath()+"/"+rotateFrameEntity.getDirectory()+"/"+rotateFrameEntity.getFileName(); /// metaConfig.getVideoFramePath() log.info("VideoFramePath{}", metaConfig.getVideoFramePath()); NormalReply res = NormalReply.newBuilder() .addTraceIds( trace_id) //.setVehicle(null) .addNewUserStates(userState) .addActionResponses(0) //这个要查查 .setGetStateType(0) .setCode(0) .setMsg("OK") .setFrameSrc(frameSrc) //从数据库中获取对应的路径 .build(); responseObserver.onNext(res); responseObserver.onCompleted(); } catch(Exception e) { e.printStackTrace(); } } //返回的是角度矫正数据 @Override public void moveStart(StartMoveRequest request, StreamObserver responseObserver) { try { /* * 1.从user表里获得当前人物所在的breakPoint_id * 2.根据breakPoint_id,从breakpoints表里获得对应的起始坐标 * 3.根据request中的clicking_action里的clicking_point(目的地)以及当前起始坐标计算出路径 * 4.返回整个路径的一段 * * */ int action_type= request.getActionType(); ClickingAction clicking_action = request.getClickingAction(); Point end = clicking_action.getClickingPoint(); State clicking_state = request.getClickingState(); String trace_id = request.getTraceId(); String user_id = request.getUserId(); UserEntity user = userService.findUserId(user_id); String appId = user.getAppId(); Long breakPointId = user.getBreakPointId(); BreakpointsEntity breakpointsEntity = breakpointsService.findByAppIdAndBreakPointId(appId,breakPointId); RotateFrameEntity rotateFrameEntity = rotateFrameService.findById(user.getFrameId()); Point start = null; //从user表里取 boolean isEnd = false; //计算路径 RouteDto po=new RouteDto(); PointPO s=new PointPO(); s.setX(Double.parseDouble(start.getX())); s.setY(Double.parseDouble(start.getY())); s.setZ(Double.parseDouble(start.getY())); PointPO e=new PointPO(); e.setX(Double.parseDouble(end.getX())); e.setY(Double.parseDouble(end.getY())); e.setZ(Double.parseDouble(end.getY())); po.setE_location(e); po.setS_location(s); po.setSceneCode(appId); JSONArray maps = GetRoute.getRoute(metaConfig.getFreespacePath()+ File.separator +appId+"_target_freespace.json", po); //处理路径数组,处理完成后放入缓存 //获得下一个要走的breakPointId Long nextbreakPointId = 0L; if (ObjectUtil.isNotNull(maps)&&maps.size()>=2){ nextbreakPointId = JSON.parseObject(JSONObject.toJSON(maps.get(1)).toString()).getLong("id"); maps.remove(0); redisCache.setCacheObject("route:"+trace_id,maps); } else { isEnd = true; } //开始返回结果,一段一段的返回(每段是两个邻居点的过渡),第一段之前还要有角度的矫正 //矫正的结果: //moveFrameService.findById() PointPO playerPoint = breakpointsEntity.getPosition(); Point playerPosition = createPoint(String.valueOf(playerPoint.getX()),String.valueOf(playerPoint.getY()),String.valueOf(playerPoint.getZ())); AnglePO playerAnglePO = user.getPlayerAngle(); AngleUe4 playerAngle = createAngle(playerAnglePO.getPitch(),playerAnglePO.getYaw(),playerAnglePO.getRoll()); Space player = createSpace(playerPosition,playerAngle); AnglePO cameraAnglePO = rotateFrameEntity.getCameraAngle(); int angle = cameraAnglePO.getYaw(); int offAngle = 0; offAngle = angle%45; if(offAngle>45-offAngle) { offAngle = 45-offAngle; } else { offAngle = -1*offAngle; } List rotateFrameEntityList = rotateFrameService.findByAppIdAndBreakPointIdBetweenFrameIndex(appId, breakPointId, angle, offAngle + angle); //循环 for(int i=0;i moveFrameEntityList = moveFrameService.findByAppIAndStartBreakPointIdAndEndBreakPointIdAndAngle(appId, breakPointId, nextbreakPointId, (int)(offAngle + angle)/45); double offsetX = endPosition.getX() - playerPoint.getX(); double offsetY = endPosition.getY() - playerPoint.getY(); double offsetZ = endPosition.getZ() - playerPoint.getZ(); for(int i=0;i responseObserver) { try { /* * 1.从user表里获得当前人物所在的breakPoint_id * 2.根据breakPoint_id,从breakpoints表里获得对应的起始坐标 * 3.根据request中的clicking_action里的clicking_point(目的地)以及当前起始坐标计算出路径 * 4.返回整个路径的一段 * * */ String user_id = request.getUserId(); String trace_id = request.getTraceId(); boolean needNext = request.getNext(); boolean isEnd = false; UserEntity user = userService.findUserId(user_id); BreakpointsEntity breakpointsEntity = breakpointsService.findByAppIdAndBreakPointId(user.getAppId(),user.getBreakPointId()); RotateFrameEntity rotateFrameEntity = rotateFrameService.findById(user.getFrameId()); //moveStart的结果参考moveStart //开始返回结果,一段一段的返回(每段是两个邻居点的过渡),第一段之前还要有角度的矫正 //矫正的结果: //moveFrameService.findById() PointPO playerPoint = breakpointsEntity.getPosition(); Point playerPosition = createPoint(String.valueOf(playerPoint.getX()),String.valueOf(playerPoint.getY()),String.valueOf(playerPoint.getZ())); AnglePO playerAnglePO = user.getPlayerAngle(); AngleUe4 playerAngle = createAngle(playerAnglePO.getPitch(),playerAnglePO.getYaw(),playerAnglePO.getRoll()); Space player = createSpace(playerPosition,playerAngle); AnglePO cameraAnglePO = rotateFrameEntity.getCameraAngle(); int angle = cameraAnglePO.getYaw(); int offAngle = 0; offAngle = angle%45; if(offAngle>45-offAngle) { offAngle = 45-offAngle; } else { offAngle = -1*offAngle; } Long nextbreakPointId = 0L; // 从缓存里面取 JSONArray cacheObject = redisCache.getCacheObject(trace_id); if (needNext&&redisCache.hasKey(trace_id)){ JSONArray cacheObject = redisCache.getCacheObject(trace_id); if (cacheObject.size()>=2){ nextbreakPointId = JSON.parseObject(JSONObject.toJSON(cacheObject.get(1)).toString()).getLong("id"); cacheObject.remove(0); redisCache.setCacheObject("route:"+trace_id,cacheObject); } else { isEnd = true; } } else { isEnd = true; } //循环 //for() PointPO cameraPoint = rotateFrameEntity.getCameraPosition(); Point cameraPosition = createPoint(String.valueOf(cameraPoint.getX()),String.valueOf(cameraPoint.getY()),String.valueOf(cameraPoint.getZ())); AngleUe4 cameraAngle = createAngle(cameraAnglePO.getPitch(),cameraAnglePO.getYaw(),cameraAnglePO.getRoll()); Space camera = createSpace(cameraPosition,cameraAngle); Point cameraCenter = createPoint(String.valueOf(playerPoint.getX()),String.valueOf(playerPoint.getY()),String.valueOf(playerPoint.getZ())); State playerState = createPlayerState( player, camera, cameraCenter); RenderInfo renderInfo = createRenderInfo(); Event event = createEvent(); UserState userState = createUserState( user_id, playerState, renderInfo, event); MoveReply res = MoveReply.newBuilder() .setTraceIds(0, trace_id) .setVehicle(null) .setNewUserStates(0, userState) .setActionResponses(0, 0) //这个要查查 .setGetStateType(0) .setCode(0) .setMsg("OK") //.setPlayer(index, value) //.setCamera(index, value) //.setCameraCenter(index, value) //.setFrameSrc(index, value) .setIsEnd(isEnd) .build(); } catch(Exception e) { e.printStackTrace(); } } @Override public void getBreakPoint(BreakPointRequest request, StreamObserver responseObserver) { try { log.info("进入{}",request); int action_type = request.getActionType(); NeighborPointsAction get_neighbor_points_action = request.getGetNeighborPointsAction(); String trace_id = request.getTraceId(); String user_id = request.getUserId(); //从表breakpoints里获取所有的呼吸点,并且是数组 //TODO 根据查询所有 UserEntity userEntity = userService.findUserId(user_id); List allList = breakpointsService.findByAppId(userEntity.getAppId()); Point[] nps=null; BreakPointReply res = BreakPointReply.newBuilder() .setActionType(action_type) .setPointType(100) .setExtra("") .setTraceId(trace_id) .setPacketId("") //.setNps(nps) .setPeopleNum(0) .setZoneId("") .setEchoMsg("") .setReserveDetail(null) //.setUserWithAvatarList() //.setNewUserStates() .setCode(0) .setMsg("") .build(); responseObserver.onNext(res); responseObserver.onCompleted(); log.info("回复{}",res); } catch(Exception e) { e.printStackTrace(); } } //操作杆 @Override public void joystick(JoystickRequest request, StreamObserver responseObserver) { try { log.info("进入{}",request); /* { "action_type": 15, "dir_action": { "move_angle": 276, "speed_level": 8 }, "trace_id": "d0a45ade-b674-47dc-a546-36e981c78ae8", "user_id": "7ef177cb55c91", "packet_id": "d3a3b46a-33cf-486f-b8aa-36b26f786eeb" } */ int actionType = request.getActionType(); DirAction dirAction = request.getDirAction(); String trace_id = request.getTraceId(); String user_id = request.getUserId(); String packet_id = request.getPacketId(); UserEntity user = userService.findUserId(user_id); Long breakPointId = user.getBreakPointId(); //获得当前点所有邻居点 //TODO 获取棋盘邻居点 getContact BreakpointsEntity breakpointsEntity = breakpointsService.findByAppIdAndBreakPointId(user.getAppId(), breakPointId); log.info("breakpointsEntity-getContact",breakpointsEntity.getContact()); //找到与角度move_angle最近的邻居点 //移动player,并且更新相机角度 } catch(Exception e) { e.printStackTrace(); } } private UserState createUserState(String user_id,State state,RenderInfo renderInfo,Event event) { UserState userState = UserState.newBuilder() .setUserId(user_id) .setPlayerState(state) .setRenderInfo(renderInfo) .setEvent(event) .setRelation(1) .build(); return userState; } private State createPlayerState(Space player,Space camera,Point cameraCenter) { State playerState = State.newBuilder() .setRoomTypeId("") .setPerson(0) .setAvatarId("") .setSkinId("") .setRoomId("") .setIsHost(false) .setIsFollowHost(false) .setSkinDataVersion("") .setAvatarComponents("") .setNickName("") .setMovingMode(0) .setAttitude("") .setAreaName("") .setPathName("") .setPathId("") .setAvatarSize(1) .setExtra("") .setPrioritySync(false) .setPlayer(player) .setCamera(camera) .setCameraCenter(cameraCenter).build(); return playerState; } private RenderInfo createRenderInfo() { RenderInfo renderInfo = RenderInfo.newBuilder() .setRenderType(0) .setVideoFrame("") .setCameraStateType(0) .setIsMoving(0) .setNeedIfr(0) .setIsVideo(0) .setStillFrame(0) .setIsRotating(0) .setIsFollowing(0) .setClientPanoTreceId("") .setPrefetchVideoId("") .setNoMedia(false).build(); return renderInfo; } private Event createEvent() { Event event = Event.newBuilder().setId("").setType(0).build(); return event; } private Space createSpace(Point position,AngleUe4 angle) { Space space = Space.newBuilder().setPosition(position).setAngle(angle).build(); return space; } private Point createPoint(String x,String y,String z) { Point point = Point.newBuilder().setX(x).setY(y).setZ(z).build(); return point; } private AngleUe4 createAngle(int pitch,int yaw,int roll) { AngleUe4 angle = AngleUe4.newBuilder().setPitch(pitch).setYaw(yaw).setRoll(roll).build(); return angle; } /** * 根据余弦定理计算线段1到线段2的夹角,线段1:起始点到原点,线段2:原点到结束点) * @param o 原点 * @param s 起始点 * @param e 结束点 * @return */ private double calAngle(JSONObject o, JSONObject s, JSONObject e) { double cosfi = 0; double fi = 0; double norm = 0; double dsx = s.getDoubleValue("x") - o.getDoubleValue("x"); double dsy = s.getDoubleValue("y") - o.getDoubleValue("y"); double dex = e.getDoubleValue("x") - o.getDoubleValue("x"); double dey = e.getDoubleValue("y") - o.getDoubleValue("y"); cosfi = dsx * dex + dsy * dey; norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey); cosfi /= Math.sqrt(norm); if (cosfi >= 1.0) return 0; if (cosfi <= -1.0) return Math.PI; fi = Math.acos(cosfi); if (180 * fi / Math.PI < 180) { return 180 * fi / Math.PI; } else { return 360 - 180 * fi / Math.PI; } } }