Modify GUA | Begin work on Mulch/Ace Games

This commit is contained in:
Julia Butenhoff 2022-07-24 22:07:11 -05:00
parent 2557b09ce1
commit 28ceb6a90c
17 changed files with 520 additions and 65 deletions

2
.gitignore vendored
View File

@ -37,4 +37,4 @@ build/
.vscode/
### Funkey Profiles ###
profiles/**/*
data/**/*

View File

@ -139,7 +139,7 @@ public class ArkOneController implements TcpHandler {
// Plugin 10 (Trunk)
case "gua":
responses.add(trunkPlugin.GetUserAssets());
responses.add(trunkPlugin.GetUserAssets(connection));
break;
case "glb":
responses.add(trunkPlugin.GetLootBalance());
@ -147,8 +147,14 @@ public class ArkOneController implements TcpHandler {
case "gfl":
responses.add(trunkPlugin.GetFamiliarsList());
break;
case "gutc":
responses.add(trunkPlugin.GetUserTransactionsCount(connection));
break;
case "gut":
responses.add(trunkPlugin.GetUserTransactions(connection));
break;
case "bf":
responses.add(trunkPlugin.BuyFamiliar(commandInfo));
responses.add(trunkPlugin.BuyFamiliar(commandInfo, connection));
break;
// Catch Unhandled Commands

View File

@ -2,6 +2,7 @@ package com.icedberries.UBFunkeysServer.ArkOne;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
@ -68,4 +69,31 @@ public class ArkOneParser {
}
return false;
}
public static Node findParentNodeOfPath(NodeList nList, String nodePath) {
ArrayList<String> path = new ArrayList<>(Arrays.asList(nodePath.split("/")));
if (path.size() <= 0) {
return null;
}
if (path.size() > 1) {
for (int i = 0; i < nList.getLength(); i++) {
Node node = nList.item(i);
if (node.getNodeName().equals(path.get(0))) {
path.remove(0);
return findParentNodeOfPath(node.getChildNodes(), String.join("/", path));
}
}
} else {
for (int i = 0; i < nList.getLength(); i++) {
Node node = nList.item(i);
if (node.getNodeName().equals(path.get(0))) {
return node;
}
}
}
// Nothing found
return null;
}
}

View File

@ -12,7 +12,6 @@ import org.springframework.util.FileCopyUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -25,8 +24,6 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Arrays;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -100,7 +97,6 @@ public class GalaxyPlugin {
resp.appendChild(rootElement);
// Continue appending to the saveData
//TODO: VERIFY THIS ELEMENT ATTRIBUTE
connection.setSaveData(element.getAttribute("v") + connection.getSaveData());
if (connection.getChunksLeft() == 1) {
@ -183,7 +179,7 @@ public class GalaxyPlugin {
profile.getDocumentElement().normalize();
switch(category) {
case 1:
Node gameNodes = findChildNodeByName(profile.getChildNodes(), "profile/statistics/games");
Node gameNodes = ArkOneParser.findParentNodeOfPath(profile.getChildNodes(), "profile/statistics/games");
for (int i = 0; i < gameNodes.getChildNodes().getLength(); i++) {
Element record = resp.createElement("record");
@ -195,7 +191,7 @@ public class GalaxyPlugin {
}
break;
case 2:
Node itemNodes = findChildNodeByName(profile.getChildNodes(), "profile/menu/items");
Node itemNodes = ArkOneParser.findParentNodeOfPath(profile.getChildNodes(), "profile/menu/items");
for (int i = 0; i < itemNodes.getChildNodes().getLength(); i++) {
Element record = resp.createElement("record");
@ -213,31 +209,4 @@ public class GalaxyPlugin {
return ArkOneParser.RemoveXMLTag(resp);
}
private Node findChildNodeByName(NodeList nList, String nodePath) {
ArrayList<String> path = new ArrayList<>(Arrays.asList(nodePath.split("/")));
if (path.size() <= 0) {
return null;
}
if (path.size() > 1) {
for (int i = 0; i < nList.getLength(); i++) {
Node node = nList.item(i);
if (node.getNodeName().equals(path.get(0))) {
path.remove(0);
return findChildNodeByName(node.getChildNodes(), String.join("/", path));
}
}
} else {
for (int i = 0; i < nList.getLength(); i++) {
Node node = nList.item(i);
if (node.getNodeName().equals(path.get(0))) {
return node;
}
}
}
// Nothing found
return null;
}
}

View File

@ -1,39 +1,121 @@
package com.icedberries.UBFunkeysServer.ArkOne.Plugins;
import com.icedberries.UBFunkeysServer.ArkOne.ArkOneParser;
import com.icedberries.UBFunkeysServer.domain.Familiar;
import com.icedberries.UBFunkeysServer.domain.User;
import com.icedberries.UBFunkeysServer.service.FamiliarService;
import com.icedberries.UBFunkeysServer.service.FileService;
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.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.util.Arrays;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
@Service
public class TrunkPlugin {
private final Integer LOOT_BALANCE = 2500;
public String GetUserAssets() {
//TODO: IMPLEMENT ME TO READ FROM USER PROFILE
private enum PurchaseType {
FAMILIAR
}
return "<h10_0><gua><m id=\"80041a\" /></gua></h10_0>";
@Autowired
Server server;
@Autowired
FileService fileService;
@Autowired
FamiliarService familiarService;
@Autowired
UserService userService;
public String GetUserAssets(Connection connection) throws ParserConfigurationException, IOException, SAXException {
//TODO: IMPLEMENT ITEMS | MOODS | JAMMERS
// Moods - Tag looks like this: <m id="80041a" />
// Append the starting tags
StringBuilder response = new StringBuilder();
response.append("<h10_0><gua>");
// Load the users save
Resource resource = fileService.load(server.getConnectedUsers().get(connection.getClientIdentifier()).getUsername() + "/profile");
// Load their save to a string
if (resource != null) {
String content;
try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) {
content = FileCopyUtils.copyToString(reader);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document profile = dBuilder.parse(new InputSource(new StringReader(content)));
profile.getDocumentElement().normalize();
// Append the familiars
Node familiarParentNode = ArkOneParser.findParentNodeOfPath(profile.getChildNodes(), "profile/trunk/familiars");
for (int i = 0; i < familiarParentNode.getChildNodes().getLength(); i++) {
Element child = (Element) familiarParentNode.getChildNodes().item(i);
String id = child.getAttribute("id");
String p = child.getAttribute("start");
String cnt = child.getAttribute("time");
// cnt -> time
// p -> start
// id -> item id
//TODO: FINISH FIXING THIS
response.append("<f id=\"" + id + "\" p=\"" + (27645298/60) + "\" c=\"" + 720 + "\" />");
}
}
// Append the ending tags
response.append("</gua></h10_0>");
return response.toString();
}
public String GetLootBalance() {
// Return a static balance that never changes
return "<h10_0><glb b=\"" + LOOT_BALANCE + "\" /></h10_0>";
}
public String GetFamiliarsList() {
// Create list of all familiar IDs
List<String> familiarIds = Arrays.asList("80036a", "80035a", "80034a", "80033a", "80032a", "80031a", "80030a",
"80029a", "80028a", "80027a", "80026a", "80025a", "80017a", "80016a", "80015a", "80007a", "80006a",
"80005a", "80004a", "80003a", "80002a", "80001a", "80000a");
// Build the list
// Get all the familiars
List<Familiar> familiars = familiarService.findAll();
// Start to build the response
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<h10_0><gfl>");
// Iterate over the IDs to append them
for (String id : familiarIds) {
stringBuilder.append("<f rid=\"" + id + "\" id=\"" + id + "\" c=\"100\" dc=\"50\" h=\"720\" d=\"false\" />");
// Iterate over the items in the familiars list to add them to the response
for (Familiar familiar : familiars) {
stringBuilder.append("<f rid=\"" + familiar.getId() + "\" id=\"" + familiar.getId() + "\" c=\""
+ familiar.getCost() + "\" dc=\"" + familiar.getDiscountedCost() + "\" h=\""
+ familiar.getDuration() + "\" d=\"\" />");
}
// Add closing tags
@ -43,8 +125,91 @@ public class TrunkPlugin {
return stringBuilder.toString();
}
public String BuyFamiliar(Element element) {
public String GetUserTransactionsCount(Connection connection) {
User user = server.getConnectedUsers().get(connection.getClientIdentifier());
// Make sure a valid user was gotten
if (user != null) {
int transactionCount = 0;
// Make sure the transaction count has been set before
if (user.getTransactionCount() != null) {
// They have a transaction count
transactionCount = user.getTransactionCount();
} else {
// Initialize it to 0
user.setTransactionCount(0);
// Update their account
userService.updateUserOnServer(connection, user);
}
return "<h10_0><gutc c=\"" + transactionCount + "\" /></h10_0>";
} else {
return "<h10_0><gutc c=\"0\" /></h10_0>";
}
}
public String GetUserTransactions(Connection connection) {
User user = server.getConnectedUsers().get(connection.getClientIdentifier());
if (user.getTransactionHistory() != null) {
return "<h10_0><gut>" + user.getTransactionHistory() + "</gut></h10_0>";
} else {
return "<h10_0><gut></gut></h10_0>";
}
}
public String BuyFamiliar(Element element, Connection connection) {
// Save this transaction to the DB
PostTransaction(connection, PurchaseType.FAMILIAR, element.getAttribute("id"));
// We always return LOOT_BALANCE so players are never charged for these items
return "<h10_0><bf id=\"" + element.getAttribute("id") + "\" b=\"" + LOOT_BALANCE + "\" /></h10_0>";
}
public void PostTransaction(Connection connection, PurchaseType purchaseType, String itemId) {
User user = server.getConnectedUsers().get(connection.getClientIdentifier());
// Get the date for this transaction
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm");
String date = now.format(formatter);
// Get the cost of the item
Integer cost = 0;
switch(purchaseType) {
case FAMILIAR:
cost = familiarService.getCostById(itemId);
break;
}
// Create a transaction xml tag
String transaction = "<t id=\"" + itemId + "\" rid=\"" + itemId + "\" d=\"" + date + "\" c=\""
+ cost + "\" b=\"" + LOOT_BALANCE + "\" />";
// Append to the user's transaction history
if(user.getTransactionHistory() == null) {
// No history yet
user.setTransactionHistory(transaction);
} else {
// Append to the existing history
user.setTransactionHistory(user.getTransactionHistory() + transaction);
}
// Save transaction
userService.updateUserOnServer(connection, user);
// Increment the transaction count for this user
IncrementTransactionCount(connection);
}
private void IncrementTransactionCount(Connection connection) {
User user = server.getConnectedUsers().get(connection.getClientIdentifier());
int newTransCount = user.getTransactionCount() + 1;
user.setTransactionCount(newTransCount);
// Update their account
userService.updateUserOnServer(connection, user);
}
}

View File

@ -47,6 +47,13 @@ public class UserPlugin {
.password(passwordEncoder.encode(password))
.securityQuestion(securityQuestion)
.securityAnswer(passwordEncoder.encode(securityAnswer))
.chatStatus(0)
.connectionId("00000000-0000-0000-0000-000000000000")
.isOnline(0)
.phoneStatus(0)
.rawBuddyList("")
.transactionCount(0)
.transactionHistory("")
.build();
// 0 - Successfully registered
@ -117,7 +124,7 @@ public class UserPlugin {
if (buddyUser == null) {
continue;
}
//TODO: VERIFY THIS BUILDS THE XML AS EXPECTED
// Get information off their data to build a xml tag
Element buddyElement = doc.createElement("buddy");
buddyElement.setAttribute("id", String.valueOf(buddyUser.getUUID()));

View File

@ -0,0 +1,49 @@
package com.icedberries.UBFunkeysServer.DatabaseSetup;
import com.icedberries.UBFunkeysServer.domain.Familiar;
import com.icedberries.UBFunkeysServer.service.FamiliarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class TrunkData {
@Autowired
FamiliarService familiarService;
// List of all familiar ids
private final List<String> familiarIds = Arrays.asList("80036a", "80035a", "80034a", "80033a", "80032a", "80031a", "80030a",
"80029a", "80028a", "80027a", "80026a", "80025a", "80017a", "80016a", "80015a", "80007a", "80006a",
"80005a", "80004a", "80003a", "80002a", "80001a", "80000a");
private final Integer FAMILIAR_COST = 100;
private final Integer FAMILIAR_DISCOUNT_COST = 50;
private final Integer FAMILIAR_DURATION = 720;
@EventListener(ApplicationReadyEvent.class)
public void insertFamiliars() {
// Iterate over the familiar ids
for (String id : familiarIds) {
// Attempt to get it from the DB
Familiar familiar = familiarService.findById(id).orElse(null);
// Only insert if the data is null
if (familiar == null) {
// Build a new familiar to insert
Familiar newFamiliar = Familiar.builder()
.id(id)
.cost(FAMILIAR_COST)
.discountedCost(FAMILIAR_DISCOUNT_COST)
.duration(FAMILIAR_DURATION)
.build();
// Save it to the db
familiarService.save(newFamiliar);
}
}
}
}

View File

@ -4,6 +4,8 @@ import com.icedberries.UBFunkeysServer.ArkOne.ArkOneParser;
import com.icedberries.UBFunkeysServer.domain.Crib;
import com.icedberries.UBFunkeysServer.service.CribService;
import com.icedberries.UBFunkeysServer.service.EmailService;
import com.icedberries.UBFunkeysServer.service.FileService;
import com.icedberries.UBFunkeysServer.util.RDFUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -11,6 +13,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -28,18 +31,13 @@ import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ThreadLocalRandom;
import static java.nio.charset.StandardCharsets.UTF_8;
@RestController
public class GalaxyServer {
@ -49,6 +47,9 @@ public class GalaxyServer {
@Autowired
private CribService cribService;
@Autowired
FileService fileService;
/**
* This is only used as part of the updater to pass files to the client as requested via URL path
*/
@ -136,9 +137,15 @@ public class GalaxyServer {
return saveCrib(nodes.item(0));
case "loadcrib":
return loadCrib((Element)nodes.item(0));
default:
System.out.println("[Galaxy][POST][ERROR] Unhandled type of request for: " + command);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
case "get_sh_levels":
return getShLevels((Element)nodes.item(0));
case "get_level":
return getLevel((Element)nodes.item(0));
case "add_level":
return addLevel((Element)nodes.item(0));
default:
System.out.println("[Galaxy][POST][ERROR] Unhandled type of request for: " + command);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
} catch (ParserConfigurationException | IOException | SAXException e) {
System.out.println("[Galaxy][POST][ERROR] Thrown Error: ");
@ -307,4 +314,33 @@ public class GalaxyServer {
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
private ResponseEntity<String> getShLevels(Element element) throws IOException {
System.out.println("[Galaxy][POST] get_sh_levels request received");
//TODO: GET THE LEVELS SAVED ON THE SERVER
return new ResponseEntity<>("<get_sh_levels r=\"0\"><level n=\"\"><level_data /></level></get_sh_levels>", HttpStatus.OK);
}
private ResponseEntity<String> getLevel(Element element) {
//TODO: DO THIS
return new ResponseEntity<>("<get_level r=\"0\"><level n=\"\"><level_data /></level></get_level>", HttpStatus.OK);
}
private ResponseEntity<String> addLevel(Element element) {
//TODO: DO THIS
return new ResponseEntity<>("<add_level r=\"0\"><level n=\"\"><level_data /></level></add_level>", HttpStatus.OK);
}
/*
// Game to get
String gamePath = element.getAttribute("tnpath").replaceFirst("data/", "");
// Load the users file
Resource resource = fileService.load(gamePath + "/uglevels.rdf");
// Load their save to a string
String content = "";
byte[] targetArray = org.apache.commons.io.IOUtils.toByteArray(resource.getInputStream());
content = RDFUtil.decode(new String(targetArray, StandardCharsets.ISO_8859_1));
*/
}

View File

@ -0,0 +1,28 @@
package com.icedberries.UBFunkeysServer.domain;
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "Familiars")
public class Familiar {
// Item ID
@Id
private String id;
private Integer cost;
private Integer discountedCost;
// This is the number of hours it lasts
private Integer duration;
}

View File

@ -5,6 +5,7 @@ import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.Type;
import javax.persistence.Column;
import javax.persistence.Entity;
@ -72,6 +73,14 @@ public class User {
// Last ping time
private LocalDateTime lastPing;
// Transaction Count
private Integer transactionCount;
// Transaction History
@Column(columnDefinition = "MEDIUMTEXT")
@Type(type = "org.hibernate.type.TextType")
private String transactionHistory;
public java.util.UUID getConnectionId() {
return java.util.UUID.fromString(connectionId);
}

View File

@ -0,0 +1,18 @@
package com.icedberries.UBFunkeysServer.repository;
import com.icedberries.UBFunkeysServer.domain.Familiar;
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;
@Repository
public interface FamiliarRepository extends CrudRepository<Familiar, String> {
List<Familiar> findAll();
@Query("select familiar.cost from Familiar familiar where familiar.id = :id")
Integer getCostById(@Param("id") String id);
}

View File

@ -0,0 +1,17 @@
package com.icedberries.UBFunkeysServer.service;
import com.icedberries.UBFunkeysServer.domain.Familiar;
import java.util.List;
import java.util.Optional;
public interface FamiliarService {
Optional<Familiar> findById(String id);
Familiar save(Familiar familiar);
List<Familiar> findAll();
Integer getCostById(String id);
}

View File

@ -10,7 +10,7 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class CribServiceImpl implements CribService {
public final CribRepository cribRepository;
private final CribRepository cribRepository;
@Override
public Integer count() {

View File

@ -0,0 +1,37 @@
package com.icedberries.UBFunkeysServer.service.impl;
import com.icedberries.UBFunkeysServer.domain.Familiar;
import com.icedberries.UBFunkeysServer.repository.FamiliarRepository;
import com.icedberries.UBFunkeysServer.service.FamiliarService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class FamiliarServiceImpl implements FamiliarService {
private final FamiliarRepository familiarRepository;
@Override
public Optional<Familiar> findById(String id) {
return familiarRepository.findById(id);
}
@Override
public Familiar save(Familiar familiar) {
return familiarRepository.save(familiar);
}
@Override
public List<Familiar> findAll() {
return familiarRepository.findAll();
}
@Override
public Integer getCostById(String id) {
return familiarRepository.getCostById(id);
}
}

View File

@ -45,7 +45,7 @@ public class FileServiceImpl implements FileService {
if (resource.exists() || resource.isReadable()) {
return resource;
} else {
throw new RuntimeException("Could not read the file!");
return null;
}
} catch(MalformedURLException e) {
throw new RuntimeException("Error: " + e.getMessage());

View File

@ -22,7 +22,6 @@ public class UserServiceImpl implements UserService {
@Autowired
Server server;
@Override
public Optional<User> findByUUID(Integer uuid) {
return userRepository.findByUUID(uuid);

File diff suppressed because one or more lines are too long