package be.demmel.jgws.actions;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import be.demmel.jgws.CharacterData;
import be.demmel.jgws.ChatColor;
import be.demmel.jgws.GameServer;
import be.demmel.jgws.GameServerSession;
import be.demmel.jgws.QueueAction;
import be.demmel.jgws.SessionKey;
import be.demmel.jgws.packets.Vector2;
import be.demmel.jgws.packets.gameserver.outbound.P021_SpawnObject;
import be.demmel.jgws.packets.gameserver.outbound.P023_InstanceLoadFadeIntoMap;
import be.demmel.jgws.packets.gameserver.outbound.P077_UpdateAgentAppearance;
import be.demmel.jgws.packets.gameserver.outbound.P081_GeneralChatMessage;
import be.demmel.jgws.packets.gameserver.outbound.P082_GeneralChatNoOwner;
import be.demmel.jgws.packets.gameserver.outbound.P098_UpdateAgentFullEquipment;
import be.demmel.jgws.packets.gameserver.outbound.P144_UpdateMorale;
import be.demmel.jgws.packets.gameserver.outbound.P154_UpdatePublicProfessions;
import be.demmel.jgws.packets.gameserver.outbound.P228_UpdateVitalStat;
public class SpawnPlayerAction implements QueueAction {
private static final Logger LOGGER = LoggerFactory.getLogger(SpawnPlayerAction.class);
private Channel newPlayerData;
private ChannelGroup channels;
public SpawnPlayerAction(Channel newPlayer, ChannelGroup channels) {
this.newPlayerData = newPlayer;
this.channels = channels;
}
@Override
public void execute() {
try {
for (Channel player :channels) {
// If this player is the one that just joined the map, treat him differently
GameServerSession playerData = newPlayerData.attr(SessionKey.SESSION_KEY).get();
if (player == this.newPlayerData) {
spawnChar(playerData.getCurrentCharacter(), player);
P023_InstanceLoadFadeIntoMap fadeIntoMap = new P023_InstanceLoadFadeIntoMap();
fadeIntoMap.setAgentId(playerData.getCurrentCharacter().getAgentID());
fadeIntoMap.setUnknown2(3);
this.newPlayerData.write(fadeIntoMap);
continue;
} else {
// It's another player, so spawn this player for the new player, and spawn him for the other
// spawn the new player for the "other" player
spawnChar(playerData.getCurrentCharacter(), player);
// spawn the "other" player for the new player
spawnChar(player.attr(SessionKey.SESSION_KEY).get().getCurrentCharacter(), this.newPlayerData);
}
}
//TODO: spawn NPCs
//TODO: spawn equipment
//TODO: party window (not complete in the C# project)
// Send the Welcome Message
String[] welcomeMessage = GameServer.WELCOME_MESSAGE;
// Send each line to the client
for (String welcomeLine : welcomeMessage) {
//List<Packet> packets = new ArrayList<>();
P081_GeneralChatMessage generalChatMessage = new P081_GeneralChatMessage();
//TODO: the prefix and suffix is always the same?
generalChatMessage.setMessage("Ĉć" + welcomeLine + '\u0001');
this.newPlayerData.write(generalChatMessage);
P082_GeneralChatNoOwner generalChatOwner = new P082_GeneralChatNoOwner();
generalChatOwner.setUnknown2(ChatColor.DARKORANGE_DARKORANGE.getValue());
this.newPlayerData.write(generalChatOwner);
//this.newPlayerData.write(packets);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void spawnChar(CharacterData newCharacter, Channel recipient) throws Exception {
P077_UpdateAgentAppearance updateAgentAppearance = new P077_UpdateAgentAppearance();
updateAgentAppearance.setUnknown1(newCharacter.getLocalID());
updateAgentAppearance.setUnknown2(newCharacter.getAgentID());
//TODO: utility method that does this, I'm sick of converting everywhere...
byte[] rawData = newCharacter.getAppearance();
//FIXME: appearance is not 4 bytes, why are we truncating the first 4 bytes??
//updateAgentAppearance.setAppearance(new short[]{(short) (rawData[0] & 0xFF), (short) (rawData[1] & 0xFF), (short) (rawData[2] & 0xFF), (short) (rawData[3] & 0xFF)});
//TODO: utility
updateAgentAppearance.setAppearance(1L | rawData[3] << 24 | rawData[2] << 16 | rawData[1] << 8 | rawData[0] & 0xFF);
updateAgentAppearance.setUnknown6(0x3cbfa094);
updateAgentAppearance.setName(newCharacter.getName());
recipient.write(updateAgentAppearance);
P021_SpawnObject spawnObject = new P021_SpawnObject();
spawnObject.setAgentId(newCharacter.getAgentID());
spawnObject.setUnknown2((0x30000000) | newCharacter.getLocalID()); // assumption that this is localID
spawnObject.setUnknown3((byte) 1);
spawnObject.setUnknown4((byte) 5);
Vector2 position = new Vector2(newCharacter.getPosition().getX(), newCharacter.getPosition().getY());
spawnObject.setPosition(position);
spawnObject.setPlane(newCharacter.getPosition().getZ());
Vector2 rotation = new Vector2(Float.MAX_VALUE, newCharacter.getRotation());
spawnObject.setRotation(rotation);
spawnObject.setUnknown8((byte) 1);
spawnObject.setSpeed(newCharacter.getSpeed());
spawnObject.setUnknown10(Float.MAX_VALUE);
spawnObject.setUnknown11(0x414000000L);
spawnObject.setUnknown12(1886151033);
Vector2 unknown19 = new Vector2(Float.MAX_VALUE, Float.MAX_VALUE);
spawnObject.setUnknown19(unknown19);
Vector2 unknown22 = new Vector2(Float.MAX_VALUE, Float.MAX_VALUE);
spawnObject.setUnknown22(unknown22);
recipient.write(spawnObject);
P098_UpdateAgentFullEquipment updateAgentFullEquipment = new P098_UpdateAgentFullEquipment();
updateAgentFullEquipment.setAgentId(newCharacter.getAgentID());
recipient.write(updateAgentFullEquipment);
P144_UpdateMorale updateMorale = new P144_UpdateMorale();
updateMorale.setAgentID(newCharacter.getAgentID());
updateMorale.setMorale(newCharacter.getMorale());
recipient.write(updateMorale);
P154_UpdatePublicProfessions updatePublicProfessions = new P154_UpdatePublicProfessions();
updatePublicProfessions.setAgentID(newCharacter.getAgentID());
updatePublicProfessions.setProfession1(newCharacter.getProfessionPrimary());
updatePublicProfessions.setProfession2(newCharacter.getProfessionSecondary());
recipient.write(updatePublicProfessions);
P228_UpdateVitalStat updateVitalStats = new P228_UpdateVitalStat();
updateVitalStats.setAgentID(newCharacter.getAgentID());
updateVitalStats.setVitalFlagsBitfield(newCharacter.getVitalStatus());
recipient.write(updateVitalStats);
}
}