Start to implement plugin 5

- Adjusted other commands to use routing plugin
- Adjusted Level to use doubles and calculate the integer value using an
  average
This commit is contained in:
2022-08-27 22:36:59 -05:00
parent c430517f7b
commit 7c09a41201
13 changed files with 360 additions and 20 deletions

View File

@@ -67,11 +67,14 @@ public class ArkOneController implements TcpHandler {
// Parse the incoming data into individual commands
List<String> commands = ArkOneParser.ParseReceivedMessage(xmlData);
// Parse out the plugin from the routing string (if it exists)
String[] routingString = ArkOneParser.ParseRoutingStrings(xmlData);
// Handle each command
for (String command : commands) {
// Remove the null character from the end if it exists
command = command.replace("\0", "");
// Parse out the plugin from the routing string (if it exists)
List<String> routingString = ArkOneParser.ParseRoutingStrings(command);
try {
Element commandInfo = (Element)ArkOneParser.ParseCommand(command);
switch(commandInfo.getNodeName()) {
@@ -210,30 +213,41 @@ public class ArkOneController implements TcpHandler {
responses.add(multiplayerPlugin.ReadyPlay());
break;
case "ms":
responses.add(multiplayerPlugin.MessageOpponent(commandInfo, connection, routingString[1]));
responses.add(multiplayerPlugin.MessageOpponent(commandInfo, connection, routingString.get(1)));
break;
case "pa":
responses.add(multiplayerPlugin.PlayAgain());
// ---------------------------- Conflict Commands --------------------------- \\
case "jn":
if (routingString[1].equals("2")) {
//TODO: IMPLEMENT CHAT - For now throw unhandled
responses.add("<unknown />");
System.out.println("[ArkOne][ERROR] Unhandled command: " + commandInfo.getNodeName());
//responses.add(chatPlugin.JoinChat());
} else {
responses.add(multiplayerPlugin.JoinGame());
switch(routingString.get(1)) {
case "2":
//TODO: IMPLEMENT CHAT - For now throw unhandled
responses.add("<unknown />");
System.out.println("[ArkOne][ERROR] Unhandled command: " + commandInfo.getNodeName());
//responses.add(chatPlugin.JoinChat());
break;
case "5":
responses.add(rainbowShootoutPlugin.JoinGame(commandInfo, connection));
break;
default:
responses.add("<unknown />");
System.out.println("[ArkOne][Error] Unhandled 'jn' route to plugin: " + routingString.get(1));
break;
}
break;
case "sp":
switch(routingString[1]) {
switch(routingString.get(1)) {
case "5":
responses.add(rainbowShootoutPlugin.ShotParameters(commandInfo));
break;
case "7":
responses.add(galaxyPlugin.SaveProfile(commandInfo, connection));
break;
default:
responses.add("<unknown />");
System.out.println("[ArkOne][Error] Unhandled 'sp' route to plugin: " + routingString.get(1));
break;
}
break;

View File

@@ -97,7 +97,19 @@ public class ArkOneParser {
return null;
}
public static String[] ParseRoutingStrings(String command) {
public static List<String> ParseRoutingStrings(String command) {
List<String> routeInfo = new ArrayList<>();
String routingString = "";
if (command.endsWith("#")) {
routingString = command.substring(command.lastIndexOf(">") + 1, command.lastIndexOf("#"));
}
if (!routingString.equals("")) {
String[] routingData = routingString.split("\\|");
routeInfo.addAll(Arrays.asList(routingData));
}
return routeInfo;
}
}

View File

@@ -2,8 +2,11 @@ package com.icedberries.UBFunkeysServer.ArkOne.Plugins.Multiplayer;
import com.icedberries.UBFunkeysServer.ArkOne.ArkOneParser;
import com.icedberries.UBFunkeysServer.ArkOne.ArkOneSender;
import com.icedberries.UBFunkeysServer.domain.Multiplayer.RainbowShootout;
import com.icedberries.UBFunkeysServer.domain.User;
import com.icedberries.UBFunkeysServer.service.RainbowShootoutService;
import com.icedberries.UBFunkeysServer.service.UserService;
import javagrinko.spring.tcp.Connection;
import javagrinko.spring.tcp.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -14,6 +17,10 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service
public class RainbowShootoutPlugin {
@@ -25,7 +32,219 @@ public class RainbowShootoutPlugin {
UserService userService;
@Autowired
private ArkOneSender arkOneSender;
ArkOneSender arkOneSender;
@Autowired
RainbowShootoutService rainbowShootoutService;
public String JoinGame(Element element, Connection connection)
throws InterruptedException, ParserConfigurationException, TransformerException {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
boolean exists = true;
int challenge = 0;
int challenger = 0;
connection.setTeamSide(5);
String c = element.getAttribute("c");
String pr = element.getAttribute("pr");
// See if there is an existing entry for this user in this table
User thisUser = server.getConnectedUsers().get(connection.getClientIdentifier());
RainbowShootout rainbowShootout = rainbowShootoutService.findByUserId(thisUser.getUUID()).orElse(null);
// If exists, grab the details or set to not exist yet
if (rainbowShootout != null) {
challenge = rainbowShootout.getChallenge();
challenger = rainbowShootout.getChallenger();
} else {
exists = false;
}
// Insert a new matchmaking entry
if (!exists || challenger == 0) {
// Build the new entry
RainbowShootout newRS = RainbowShootout.builder()
.username(thisUser.getUsername())
.userId(thisUser.getUUID())
.challenge(Integer.valueOf(c))
.playerInfo(pr)
.ready(0)
.score(0)
.build();
// Can't be set as part of the builder
newRS.setConnectionId(thisUser.getConnectionId());
// Save to the DB
rainbowShootoutService.save(newRS);
}
// Random Matchmaking
if (c.equals("0") && challenge != 1) {
String opponentName = "";
String opponentInfo = "";
Integer isPlayerFound = 0;
int i = 0;
// Time to look for a match
while (i < 30) {
// Get open players
List<RainbowShootout> openPlayers = rainbowShootoutService.findOtherOpenPlayers(thisUser.getUUID());
if (openPlayers.size() > 0) {
// Get a random open one
Random rand = new Random();
RainbowShootout randomElement = openPlayers.get(rand.nextInt(openPlayers.size()));
// Save information about the opponent
connection.setOpponentUID(randomElement.getUserId());
connection.setOpponentConID(randomElement.getConnectionId());
opponentName = randomElement.getUsername();
opponentInfo = randomElement.getPlayerInfo();
// Get my data
RainbowShootout myRS = rainbowShootoutService.findByUserId(thisUser.getUUID()).orElse(null);
if (myRS != null) {
isPlayerFound = myRS.getChallenge();
}
}
// See if we found an opponent
if (connection.getOpponentConIDAsString().equals("") && isPlayerFound == 0) {
TimeUnit.SECONDS.sleep(1);
i++;
} else {
i = 30;
}
}
// If player found an opponent
if (!connection.getOpponentConIDAsString().equals("")) {
// Update the matchmaking entries to reflect the found match
RainbowShootout myRS = rainbowShootoutService.findByUserId(thisUser.getUUID()).orElse(null);
RainbowShootout oppRS = rainbowShootoutService.findByUserId(connection.getOpponentUID()).orElse(null);
if (myRS != null) {
myRS.setChallenger(connection.getOpponentUID());
}
if (oppRS != null) {
oppRS.setChallenger(thisUser.getUUID());
}
rainbowShootoutService.save(myRS);
rainbowShootoutService.save(oppRS);
// Build the response to send to the opponent
Document resp1 = dBuilder.newDocument();
Element rootElement = resp1.createElement("h5_0");
resp1.appendChild(rootElement);
Element ojElement = resp1.createElement("oj");
ojElement.setAttribute("n", thisUser.getUsername());
ojElement.setAttribute("pr", pr);
rootElement.appendChild(ojElement);
arkOneSender.SendToUser(connection.getOpponentConIDAsUUID(), ArkOneParser.RemoveXMLTag(resp1));
// Build the response to this user
Document resp2 = dBuilder.newDocument();
Element rootElement2 = resp2.createElement("h5_0");
resp2.appendChild(rootElement2);
Element jnElement = resp2.createElement("jn");
jnElement.setAttribute("r", "0");
rootElement2.appendChild(jnElement);
Element ojElement2 = resp2.createElement("oj");
ojElement2.setAttribute("n", opponentName);
ojElement2.setAttribute("pr", opponentInfo);
rootElement2.appendChild(ojElement2);
return ArkOneParser.RemoveXMLTag(resp2);
}
// If found by another player
else if (isPlayerFound == 1) {
RainbowShootout myRS = rainbowShootoutService.findByUserId(thisUser.getUUID()).orElse(null);
if (myRS != null) {
connection.setOpponentUID(myRS.getChallenger());
RainbowShootout oppRS = rainbowShootoutService.findByUserId(connection.getOpponentUID()).orElse(null);
if (oppRS != null) {
connection.setOpponentConID(oppRS.getConnectionId());
}
}
return "<mm_found />";
}
// Matchmaking timed out
else {
return "<mm_timeout />";
}
}
// If joining from invite
if (challenge == 1) {
String conID = "";
String opponentName = "";
String opponentInfo = "";
User opponent = userService.findByUUID(challenger).orElse(null);
if (opponent != null) {
opponentName = opponent.getUsername();
if (opponent.getIsOnline() == 1) {
conID = opponent.getConnectionId().toString();
}
}
RainbowShootout myRS = rainbowShootoutService.findByUserId(thisUser.getUUID()).orElse(null);
if (myRS != null) {
opponentInfo = myRS.getChallengerInfo();
RainbowShootout oppRS = rainbowShootoutService.findByUserId(challenger).orElse(null);
if (oppRS != null) {
oppRS.setChallengerInfo(pr);
myRS.setConnectionId(connection.getClientIdentifier());
rainbowShootoutService.save(oppRS);
rainbowShootoutService.save(myRS);
}
}
connection.setOpponentConID(UUID.fromString(conID));
connection.setOpponentUID(challenger);
// Build the response to send to the opponent
Document resp1 = dBuilder.newDocument();
Element rootElement = resp1.createElement("h5_0");
resp1.appendChild(rootElement);
Element ojElement = resp1.createElement("oj");
ojElement.setAttribute("n", thisUser.getUsername());
ojElement.setAttribute("pr", pr);
rootElement.appendChild(ojElement);
arkOneSender.SendToUser(connection.getOpponentConIDAsUUID(), ArkOneParser.RemoveXMLTag(resp1));
// Build the response to this user
Document resp2 = dBuilder.newDocument();
Element rootElement2 = resp2.createElement("h5_0");
resp2.appendChild(rootElement2);
Element jnElement = resp2.createElement("jn");
jnElement.setAttribute("r", "0");
rootElement2.appendChild(jnElement);
Element ojElement2 = resp2.createElement("oj");
ojElement2.setAttribute("n", opponentName);
ojElement2.setAttribute("pr", opponentInfo);
rootElement2.appendChild(ojElement2);
return ArkOneParser.RemoveXMLTag(resp2);
}
Document resp = dBuilder.newDocument();
Element rootElement = resp.createElement("h5_0");
resp.appendChild(rootElement);
Element jnElement = resp.createElement("jn");
jnElement.setAttribute("r", "0");
rootElement.appendChild(jnElement);
return ArkOneParser.RemoveXMLTag(resp);
}
public String ShotParameters(Element element) throws ParserConfigurationException,
TransformerException {

View File

@@ -439,6 +439,7 @@ public class GalaxyServer {
.sharedDate(LocalDateTime.now())
.imagePath(tnurl)
.rating(0)
.ratingCount(0)
.playCount(0)
.pos(0)
.build();

View File

@@ -4,6 +4,7 @@ import com.icedberries.UBFunkeysServer.domain.Multiplayer.RainbowShootout;
import com.icedberries.UBFunkeysServer.domain.User;
import com.icedberries.UBFunkeysServer.service.RainbowShootoutService;
import com.icedberries.UBFunkeysServer.service.UserService;
import javagrinko.spring.tcp.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
@@ -17,6 +18,9 @@ import java.util.List;
@Component
public class DatabaseCleanup {
@Autowired
Server server;
@Autowired
UserService userService;
@@ -49,7 +53,7 @@ public class DatabaseCleanup {
// Calculate how many milliseconds since last ping/login
long difference = Math.abs(Duration.between(user.getLastPing(), LocalDateTime.now()).toMillis());
if (difference > 60000) {
// USer has been online for more than 60 seconds without a new ping - set them offline
// User has been online for more than 60 seconds without a new ping - set them offline
user.setIsOnline(0);
userService.save(user);
}
@@ -67,10 +71,14 @@ public class DatabaseCleanup {
public void clearOpenMultiplayerMatchmaking() {
// Get all open multiplayer matchmaking entries in all tables
List<RainbowShootout> openRainbowShootout = rainbowShootoutService.findAll();
List<User> onlineUsers = userService.getOnlineUsers();
// Iterate over each game's entries
for (RainbowShootout rainbowShootout : openRainbowShootout) {
rainbowShootoutService.delete(rainbowShootout);
User rsUser = userService.findByUUID(rainbowShootout.getUserId()).orElse(null);
if (rsUser == null || !onlineUsers.contains(rsUser)) {
rainbowShootoutService.delete(rainbowShootout);
}
}
}
}

View File

@@ -36,9 +36,20 @@ public class Level {
private String imagePath;
// 0 -> 5 "stars"
private Integer rating;
private double rating;
private Integer ratingCount;
private Integer playCount;
private Integer pos;
public Integer getRating() {
if (rating <= 0) {
return 0;
}
double average = rating / ratingCount;
return (int)Math.rint(average);
}
}

View File

@@ -43,7 +43,7 @@ public class RainbowShootout {
private Integer score;
// If the user is ready to start the round
private String ready;
private Integer ready;
public java.util.UUID getConnectionId() {
return java.util.UUID.fromString(connectionId);

View File

@@ -1,15 +1,23 @@
package com.icedberries.UBFunkeysServer.repository;
import com.icedberries.UBFunkeysServer.domain.Multiplayer.RainbowShootout;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface RainbowShootoutRepository extends CrudRepository<RainbowShootout, Integer> {
List<RainbowShootout> findAll();
@Query("select rainbowShootout from RainbowShootout rainbowShootout where rainbowShootout.userId = :uuid")
Optional<RainbowShootout> findByUserId(@Param("uuid") Integer uuid);
@Query("select rainbowShootout from RainbowShootout rainbowShootout"
+ " where rainbowShootout.challenge = 0 and not rainbowShootout.userId = :uuid")
List<RainbowShootout> findOtherOpenPlayers(@Param("uuid") Integer uuid);
}

View File

@@ -3,10 +3,17 @@ package com.icedberries.UBFunkeysServer.service;
import com.icedberries.UBFunkeysServer.domain.Multiplayer.RainbowShootout;
import java.util.List;
import java.util.Optional;
public interface RainbowShootoutService {
List<RainbowShootout> findAll();
void delete(RainbowShootout rainbowShootout);
Optional<RainbowShootout> findByUserId(Integer userId);
RainbowShootout save(RainbowShootout rainbowShootout);
List<RainbowShootout> findOtherOpenPlayers(Integer uuid);
}

View File

@@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
@@ -23,4 +24,19 @@ public class RainbowShootoutServiceImpl implements RainbowShootoutService {
public void delete(RainbowShootout rainbowShootout) {
rainbowShootoutRepository.delete(rainbowShootout);
}
@Override
public Optional<RainbowShootout> findByUserId(Integer userId) {
return rainbowShootoutRepository.findByUserId(userId);
}
@Override
public RainbowShootout save(RainbowShootout rainbowShootout) {
return rainbowShootoutRepository.save(rainbowShootout);
}
@Override
public List<RainbowShootout> findOtherOpenPlayers(Integer uuid) {
return rainbowShootoutRepository.findOtherOpenPlayers(uuid);
}
}

View File

@@ -3,6 +3,7 @@ package javagrinko.spring.tcp;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.UUID;
public interface Connection {
@@ -15,9 +16,15 @@ public interface Connection {
void setClientIdentifier(UUID newId);
Integer getChunksLeft();
void setChunksLeft(Integer chunksLeft);
Integer getTeamSide();
void setTeamSide(Integer teamSide);
String getSaveData();
void setSaveData(String saveData);
void setOpponentUID(Integer opponentUID);
Integer getOpponentUID();
void setOpponentConID(UUID opponentConID);
String getOpponentConIDAsString();
UUID getOpponentConIDAsUUID();
interface Listener {
void messageReceived(Connection connection, byte[] bytes)
throws InvocationTargetException, IllegalAccessException;

View File

@@ -15,7 +15,6 @@ public interface Server {
List<Connection> getConnections();
void addListener(Connection.Listener listener);
HashMap<UUID, User> getConnectedUsers();
void addConnectedUser(UUID uuid, User user);
void removeConnectedUser(UUID uuid);
}

View File

@@ -21,6 +21,9 @@ public class TcpConnection implements Connection {
private Socket socket;
private List<Listener> listeners = new CopyOnWriteArrayList<>();
private UUID clientIdentifier = null;
private Integer teamSide = 5;
private Integer opponentUID;
private String opponentConID = "";
private Integer chunksLeft = 0;
private String saveData = "";
@@ -118,6 +121,16 @@ public class TcpConnection implements Connection {
this.chunksLeft = chunksLeft;
}
@Override
public Integer getTeamSide() {
return teamSide;
}
@Override
public void setTeamSide(Integer teamSide) {
this.teamSide = teamSide;
}
@Override
public String getSaveData() {
return saveData;
@@ -127,4 +140,29 @@ public class TcpConnection implements Connection {
public void setSaveData(String saveData) {
this.saveData = saveData;
}
@Override
public void setOpponentUID(Integer opponentUID) {
this.opponentUID = opponentUID;
}
@Override
public Integer getOpponentUID() {
return opponentUID;
}
@Override
public void setOpponentConID(UUID opponentConID) {
this.opponentConID = opponentConID.toString();
}
@Override
public String getOpponentConIDAsString() {
return opponentConID;
}
@Override
public UUID getOpponentConIDAsUUID() {
return UUID.fromString(opponentConID);
}
}