2025-01-29 04:29:46 +03:00

280 lines
13 KiB
Java

package com.alterdekim.game.component;
import com.alterdekim.game.component.game.*;
import com.alterdekim.game.component.rtmp.ConnectedProcessor;
import com.alterdekim.game.message.*;
import com.alterdekim.game.message.amf.AMFDeserializer;
import com.alterdekim.game.message.amf.AMFObject;
import com.alterdekim.game.message.amf.AMFSerializer;
import com.alterdekim.game.message.amf.AMFValueType;
import com.alterdekim.game.security.AuthenticationUtil;
import com.alterdekim.game.service.LocationService;
import com.alterdekim.game.service.RelationshipService;
import com.alterdekim.game.service.UserService;
import com.alterdekim.game.utils.GameUtils;
import com.alterdekim.game.utils.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
public class GameServer {
@Autowired
private UserService users;
@Autowired
private LocationService locationService;
@Autowired
private RelationshipService relationshipService;
private final Map<Long, Player> players;
private final ObjectMapper xmlMapper;
public GameServer() {
this.players = new HashMap<>();
this.xmlMapper = new XmlMapper().registerModule(new JavaTimeModule());
}
public void onConnect(long playerId, String hwId, ConnectedProcessor connectedProcessor) {
log.warn("GameServer.onConnect() connect: {}", playerId);
Optional<String> username = users.getUsernameById(playerId);
if( username.isEmpty() || !AuthenticationUtil.hwIdAuth(users.findByUsername(username.get()), hwId) || this.players.containsKey(playerId) ) {
connectedProcessor.close();
return;
}
this.players.put(playerId, new Player(connectedProcessor, username.get()));
}
public void onMessage(long playerId, List<AMFObject> params ) {
try {
log.info("GameServer.onMessage() pid: {}, params: {}", playerId, params);
switch(CommandType.fromString( (String) params.get(0).getValue() )) {
case UserCommand:
processUserMessage(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), UserMessage.class));
break;
case SetLocation:
setPlayerLocation(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), SetLocationMessage.class));
break;
case SetUserAvatarState:
setPlayerAvatarState(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), SetPlayerAvatarState.class));
break;
case SetUserAvatarPosition:
setPlayerAvatarPosition(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), SetPlayerAvatarPosition.class));
break;
default:
log.warn("GameServer.onMessage() unknown command: {}", params.get(0));
}
} catch (Exception e) {
log.error("GameServer.onMessage() error: {}", e.getMessage(), e);
}
}
private void setPlayerAvatarPosition(long playerId, SetPlayerAvatarPosition message) {
players.get(playerId).setX((Double) message.getCoordinates().get("x").getValue());
players.get(playerId).setY((Double) message.getCoordinates().get("y").getValue());
this.sendInPlayersLocation(playerId, CommandType.SetUserAvatarPosition,
new SetPlayerPosition(
playerId,
new Point((Double) message.getCoordinates().get("x").getValue(), (Double) message.getCoordinates().get("y").getValue()),
message.getTweenerId().longValue()
)
);
}
private void setPlayerAvatarState(long playerId, SetPlayerAvatarState message) {
players.get(playerId).setState(message.getState());
this.sendInPlayersLocation(playerId, CommandType.SetUserAvatarState,
new SetPlayerState(playerId, message.getState())
);
}
private void processUserMessage(long playerId, UserMessage message) throws JsonProcessingException {
log.info("GameServer.processUserMessage() message: {}", message);
switch (UserCommandType.fromString(message.getCommandType())) {
case GetUserInitData:
String r = xmlMapper.writeValueAsString(users.getUserInitInfoByUserId(playerId));
this.sendResult(playerId, message.getTransactionId(), r);
break;
case UserFriendsGet: // todo: implement
this.sendResult(playerId, message.getTransactionId(), new HashMap<>());
break;
case UserFriendsRequests: // todo: implement
this.sendResult(playerId, message.getTransactionId(), new HashMap<>());
break;
case GetClubMap: // todo: implement
this.sendResult(playerId, message.getTransactionId(), "</clubmap>");
break;
case GetFriendPanelData:
this.sendResult(playerId, message.getTransactionId(), "");
break;
case UpdateUserData:
this.sendResult(playerId, message.getTransactionId(), null);
break;
case GetUserLocation:
double prevLocation = (Double) message.getArguments().get(2).getValue();
if( prevLocation == 0.0d ) {
this.sendResult(playerId,
message.getTransactionId(),
xmlMapper.writeValueAsString(
locationService.getDefaultLocation()
)
);
}
break;
case ChatMessage:
String text = (String) message.getArguments().get(1).getValue();
sendInPlayersLocation(playerId, CommandType.ChatMessage, new ChatMessage(playerId, text));
break;
case Shoot:
if( message.getSrv().equals("ROOM") ) {
double x = (double) message.getArguments().get(1).getValue();
double y = (double) message.getArguments().get(2).getValue();
sendInPlayersLocation(playerId, CommandType.Shoot, new Shoot(playerId, x, y));
break;
}
this.sendInPlayersLocation(playerId, CommandType.SetUserAvatarState,
new SetPlayerState(playerId, players.get(playerId).getState())
);
this.users.setWeaponsCount(playerId, this.users.getIntegerUserProperty(playerId, PlayerProperties.WeaponsCount, 15)-1);
break;
// todo: bodypart colors are not appears. fix that
case GetUserInfo:
getUserInfo(playerId, ((Double) message.getArguments().get(0).getValue()).longValue(), message);
break;
case GetUserAvatar:
getAvatar(playerId, message);
break;
case GetOnlineUserFriends:
// todo: implement
break;
case GetSnInvitePanelData:
break;
case GetGrantBlocks:
// todo: implement
break;
case UseMagicAbility:
this.sendInPlayersLocation(playerId, CommandType.UseMagicAbility, new UseMagicAbility(
Long.parseLong((String) message.getArguments().get(0).getValue()),
((Double) message.getArguments().get(1).getValue()).intValue()
));
break;
case SetDefaultUserPhone:
long phoneId = ((Double) message.getArguments().get(0).getValue()).longValue();
this.users.setDefaultPhone(playerId, phoneId);
break;
case SetUserBackground:
long bgId = ((Double) message.getArguments().get(0).getValue()).longValue();
this.users.setDefaultBackground(playerId, bgId);
break;
case QueryUserFriendship:
long participantId = ((Double) message.getArguments().get(0).getValue()).longValue();
relationshipService.sendRequest(playerId, participantId);
break;
}
}
private void getAvatar(long playerId, UserMessage message) throws JsonProcessingException {
String r = xmlMapper.writeValueAsString(users.getUserAvatarByUserId(playerId));
r = r.substring(13);
r = r.substring(0, r.length() - 14);
log.info("getAvatar: {}", r);
this.sendResult(playerId, message.getTransactionId(), r);
}
private void getUserInfo(long playerId, long targetId, UserMessage message) throws JsonProcessingException {
String r = xmlMapper.writeValueAsString(new GetUserInfo(users.getUserInfoByUserId(targetId, false), users.getOtherUserAvatar(targetId)));
r = r.substring(11);
r = r.substring(0, r.length()-12);
log.info("getUserInfo: {}", r);
this.sendResult(playerId, message.getTransactionId(), r);
}
private void setPlayerLocation(long playerId, SetLocationMessage message) {
Player p = this.players.get(playerId);
this.deleteSelf(playerId, p.getLocationId());
int prevLocation = p.getLocationId();
p.setLocationId(GameUtils.extractLocationId(message.getLocation()));
p.setX((Double) message.getCoordinates().get("x").getValue());
p.setY((Double) message.getCoordinates().get("y").getValue());
p.setState(message.getStartState());
this.updateLocationPlayers(playerId, prevLocation);
this.sendResult(playerId, message.getTransactionId(), "");
}
private void deleteSelf(long playerId, int locationId) {
this.sendInLocation(locationId, CommandType.RemoveUserFromLocation, playerId);
}
private void updateLocationPlayers(long playerId, int prevLocation) {
int locationId = this.players.get(playerId).getLocationId();
this.sendInLocation(prevLocation, CommandType.RemoveUserFromLocation, playerId);
for( int i = 0; i < 5; i++ ) {
this.sendInPlayersLocation(playerId, CommandType.AddUserToLocation, new AddUserToLocation(
playerId,
users.getAvatarById(playerId, this.players.get(playerId))
));
}
this.players.keySet().forEach(pid -> {
Player p = this.players.get(pid);
if( p.getLocationId() != locationId ) return;
this.call(playerId, CommandType.AddUserToLocation, new AddUserToLocation(
pid,
users.getAvatarById(pid, this.players.get(pid))
));
this.call(playerId, CommandType.SetUserAvatarState, new SetPlayerState(
pid,
this.players.get(pid).getState()
));
});
}
private void sendInPlayersLocation(long playerId, CommandType type, Object obj) {
this.sendInLocation(players.get(playerId).getLocationId(), type, obj);
}
private void sendInLocation(int locationId, CommandType type, Object obj) {
players.keySet().forEach(k -> {
if( locationId != players.get(k).getLocationId() ) return;
this.call(k, type, obj);
});
}
private void sendResult(long playerId, double tid, Object obj) {
this.sendMessage(playerId, new CallMessage("_result", tid, null, obj));
}
private void call(long playerId, CommandType function, Object obj) {
this.sendMessage(playerId, new CallMessage(function.getValue(), 0d, null, obj));
}
private void sendMessage(long playerId, Object obj) {
try {
this.players.get(playerId)
.getConnection()
.write_packet(AMFSerializer.serialize(obj));
} catch (IOException e) {
log.error("Unable to send message: {}", e.getMessage());
}
}
public void onDisconnect(long playerId) {
log.warn("GameServer.onDisconnect() close: {}", playerId);
if( !this.players.containsKey(playerId) ) return;
this.deleteSelf(playerId, this.players.get(playerId).getLocationId());
this.players.remove(playerId);
}
}