Compare commits

..

76 Commits

Author SHA1 Message Date
dde0d8fa38 House inventory update 2025-04-03 19:01:05 +03:00
11c0c3d97b readme x3 2025-03-26 03:20:23 +03:00
0646859959 readme x2 2025-03-26 03:17:37 +03:00
17c9af6414 House update 2025-03-26 03:14:40 +03:00
31a02be28a Old client (2012) work 2025-03-11 01:07:38 +03:00
334e098dba Multiplayer minigames started 2025-03-10 20:50:49 +03:00
efce5e9c11 Inventory management added (admin) 2025-03-10 16:11:25 +03:00
97ef45b9a7 MiniGames (singleplayer) added 2025-03-09 19:42:09 +03:00
7440d33ddd MiniGames (singleplayer) added 2025-03-09 18:02:53 +03:00
cd5c4779c7 Goods purchasing fixed 2025-03-08 21:01:06 +03:00
dd2fafd05f Admin panel user properties editing added 2025-03-08 19:54:49 +03:00
ab080773c8 LocationsObjects bugfix 2025-03-06 21:09:54 +03:00
f5e313dda3 LocationsObjects fully added 2025-03-06 20:49:53 +03:00
5f6563d356 Changed home id logic 2025-03-06 20:16:06 +03:00
25f5e2603e Changed AMFObject value conversion 2025-03-06 16:27:35 +03:00
9c8de427ef Changed playerIds from Long to Integer 2025-03-06 16:02:59 +03:00
b999f34e1c Location stuff 2025-03-05 19:30:52 +03:00
97233286aa Useful patch for goodtype sorting 2025-03-05 18:32:47 +03:00
27a7cbd2d3 IsHomeLocked update 2025-03-05 03:04:15 +03:00
18cb96d21f README editing 2025-03-03 19:15:17 +03:00
d378a2761a Buy stuff continuation 2025-03-03 19:12:21 +03:00
2941d33d12 Buy stuff started 2025-03-03 03:12:22 +03:00
c4e04b2ea5 House stuff added 2025-03-03 02:10:05 +03:00
93b7767792 Location objects manager added 2025-03-02 02:41:16 +03:00
b6c306e791 Location objects added 2025-03-01 17:45:16 +03:00
3b63b0d32e Locations stuff and shop 2025-03-01 01:59:45 +03:00
a6b7080561 Inventory saving 2025-02-28 20:18:18 +03:00
36f9be189e Send incompatibles for user profile editor. 2025-02-28 17:38:41 +03:00
97770386e2 Send empty for some types of bodyparts. 2025-02-28 16:59:09 +03:00
faeac06f35 Tickets update 2025-02-20 03:50:11 +03:00
d9f2bc8bb0 Postcards implemented 2025-02-20 03:06:05 +03:00
904a46be77 Phone messages 2025-02-20 02:32:25 +03:00
67480abf51 Friends request bugfix 2025-02-09 03:47:02 +03:00
19590c6f88 Refactor 2025-02-09 03:23:06 +03:00
534a2d0fc3 Layout fix 2025-02-08 01:47:18 +03:00
0a39a65fc6 RTMP update 2025-02-08 01:17:50 +03:00
679ed915bf Locations added to control panel 2025-02-06 17:44:47 +03:00
95f3eb887d Bans implemented 2025-02-03 03:42:42 +03:00
5c2ffca131 RTMP patch 2025-02-03 03:26:36 +03:00
79e1f3fd8f friends implementation completed. AMFDeserializer was rewritten. 2025-02-02 04:39:31 +03:00
a756325143 friends implementation continuation 2025-02-02 02:01:34 +03:00
1a467d3046 friends implementation started 2025-02-01 03:28:51 +03:00
ae1b5beaf1 small fix 2025-02-01 03:22:04 +03:00
80ec077281 Roles fix 2025-02-01 03:14:52 +03:00
f429760030 Control panel functionality added. 2025-02-01 02:00:43 +03:00
265bc1d608 SQL formatting 2025-01-31 19:39:18 +03:00
dfaffa20f6 refactor x2 2025-01-31 18:30:56 +03:00
946b274a36 refactor 2025-01-31 18:27:24 +03:00
c4c8fce78e Stream API 2 SQL transition started. Interface proxies 2025-01-31 18:18:49 +03:00
a1fb8b6cb2 Stream API 2 SQL transition started. 2025-01-31 03:49:40 +03:00
6b3215663d ServerAction camalCase fix x2 2025-01-30 23:09:47 +03:00
da0457d91f ServerAction camalCase fix 2025-01-30 23:00:41 +03:00
e8ba711ff4 Colors in profile bug fix. 2025-01-30 22:48:03 +03:00
567911dc92 Start of database modification. 2025-01-30 22:21:43 +03:00
ac2f62389f another set of dashboard changes 2025-01-30 07:08:38 +03:00
75151c3af4 another set of dashboard changes 2025-01-30 07:02:58 +03:00
b672545495 Dashboard changes, preloaders added 2025-01-30 05:20:22 +03:00
3aa7521901 Dashboard changes 2025-01-30 00:14:27 +03:00
d425583a7e Control panel started x2 2025-01-30 00:13:27 +03:00
883457522d Control panel started 2025-01-29 04:44:52 +03:00
94247c9372 Fixed compile error 2025-01-29 04:29:46 +03:00
b00a1f5cdd Removed code blobs 2025-01-29 04:28:18 +03:00
9fe71de507 Friendship implementation started. Also small bugfixes 2025-01-29 04:10:46 +03:00
5557b125d6 Fixed bugs and etc. 2025-01-29 02:52:41 +03:00
b039a698e8 Added online status and phone skins to the database. 2025-01-29 01:33:09 +03:00
01bec2adce Reducing hardcode x2 2025-01-28 21:38:18 +03:00
46648bc08d Reducing hardcode 2025-01-28 20:13:18 +03:00
40806beb70 Implemented _AG & _UI requests 2025-01-28 19:39:09 +03:00
728d9fe108 Patches 2025-01-24 04:17:42 +03:00
d885c430e7 Edited README.md x3 2025-01-24 03:42:02 +03:00
59be29d337 Edited README.md x2 2025-01-24 03:33:09 +03:00
411a4795dc Edited README.md 2025-01-24 03:28:55 +03:00
06a76bc1c4 Added README.md x4 2025-01-23 03:35:35 +03:00
c3a5d11da7 Added README.md x3 2025-01-23 03:34:18 +03:00
8ad482bfed Added README.md x2 2025-01-23 03:31:30 +03:00
56f80292bd Added README.md 2025-01-23 03:29:27 +03:00
238 changed files with 8177 additions and 1406 deletions

2
.gitignore vendored
View File

@ -27,6 +27,8 @@ build/
### VS Code ###
.vscode/
last.log
### Mac OS ###
.DS_Store
/cache/

View File

@ -1,5 +1,64 @@
![](https://p.w0n.zip/file/b4rB1e)
![](https://p.w0n.zip/file/bkRQ6a)
![](https://p.w0n.zip/file/b6QPna)
# Shararam server
> Feels like a distant memory
<p align="center">
<img align="center" src="https://w0n.zip/file/5eVXOb">
</p>
<p align="center">Feels like a distant memory</p>
![Gitea Last Commit](https://img.shields.io/gitea/last-commit/alterwain/WhimsyWorld?gitea_url=https%3A%2F%2Fgitea.awain.net)
![Jenkins Build](https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fjenkins.awain.net%2Fjob%2FWhimsyWorld&link=https%3A%2F%2Fjenkins.awain.net%2Fjob%2FWhimsyWorld)
![Contact](https://img.shields.io/badge/xmpp-alterwain-red?link=xmpp%3Aalterwain%40awain.net%3Fomemo-sid-687809972%3Dfc938d0c120affd1f011a1f1e53449b8b773ac7c322667f1dca2b2539987b86c)
An unofficial server for semi-famous game Rolypolyland (Shararam). Remake by alterwain. Original by cl0zzzy (also me, but in 2018).
## Caution
> Anything you will do with this software is completely your responsibility. We **do not** provide any technical support, nor we don't responsible for consequences you will face due to hosting of this server (Malfunction of your computer, lawsuit, data corruption).
>
>
> To avoid nasty aftermath, consider sharing access to instance of this server only to people you trust.
>
> **We also don't have any paid services.**
>
> We only distribute software on [GitHub](https://github.com/) and [Gitea](https://gitea.awain.net/alterwain/WhimsyWorld).
>
> If you would like to have a little chat about this project, here's XMPP: [wworld@chat.awain.net](xmpp:wworld@chat.awain.net?join)
## Table of contents
- [Usage](#usage)
- [Configuration](#configuration)
- [Installation](#installation)
- [Build from source](#build)
- [Dependencies](#dependencies)
- [Gallery](#gallery)
- [License](#license)
## Usage
## Configuration
### Reverse proxy configuration
### Set external flash assets url
### Control panel
## Installation
### Using script
### Using build from jenkins
## Build
## Dependencies
- [**SWFDissect**](https://gitea.awain.net/alterwain/SWFDissect) - my self written library, made for decompilation and compilation of Flash .swf files.
## Gallery
<img src="https://w0n.zip/file/bmooEe">
<img src="https://w0n.zip/file/e3xJOa">
## License
This project is distributed under [GNU AGPLv3](https://www.gnu.org/licenses/agpl-3.0.txt) license.

View File

@ -46,8 +46,6 @@
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -153,8 +151,8 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>14</source>
<target>14</target>
<source>15</source>
<target>15</target>
</configuration>
</plugin>
</plugins>

View File

@ -1,28 +1,45 @@
package com.alterdekim.game.component;
import com.alterdekim.game.component.game.*;
import com.alterdekim.game.component.game.friends.OneFR;
import com.alterdekim.game.component.game.friends.UserFriend;
import com.alterdekim.game.component.game.home.HomeInventoryGroup;
import com.alterdekim.game.component.game.home.HomeLocation;
import com.alterdekim.game.component.game.home.HomeStuff;
import com.alterdekim.game.component.game.inventory.BuyGoodResult;
import com.alterdekim.game.component.game.inventory.BuyGoodResultGood;
import com.alterdekim.game.component.game.minigame.MiniGameAction;
import com.alterdekim.game.component.game.minigame.MultiplayerMinigameLaunch;
import com.alterdekim.game.component.game.minigame.MultiplayerMinigameWaiting;
import com.alterdekim.game.component.game.response.init.GetUserInfo;
import com.alterdekim.game.component.game.response.location.AddUserToLocation;
import com.alterdekim.game.component.rtmp.ConnectedProcessor;
import com.alterdekim.game.entity.Good;
import com.alterdekim.game.entity.PhoneMessage;
import com.alterdekim.game.entity.Postcard;
import com.alterdekim.game.message.*;
import com.alterdekim.game.message.amf.AMFDeserializer;
import com.alterdekim.game.message.amf.AMFMapper;
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.UserService;
import com.alterdekim.game.service.*;
import com.alterdekim.game.utils.GameUtils;
import com.alterdekim.game.utils.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
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.javatuples.Pair;
import org.javatuples.Triplet;
import org.javatuples.Tuple;
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;
import java.util.stream.Stream;
@Slf4j
@Component
@ -34,37 +51,58 @@ public class GameServer {
@Autowired
private LocationService locationService;
private Map<Long, Player> players;
@Autowired
private RelationshipService relationshipService;
@Autowired
private PhoneMessageService phoneMessageService;
@Autowired
private PostcardService postcardService;
@Autowired
private GoodsService goodsService;
@Autowired
private MiniGameService miniGameService;
@Autowired
private HomeInventoryService homeInventoryService;
private final Map<Integer, 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) {
public void onConnect(int 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) ) {
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 ) {
public void onMessage(int playerId, List<AMFObject> params ) {
try {
log.info("GameServer.onMessage() pid: {}, params: {}", playerId, params);
switch(CommandType.fromString( (String) params.get(0).getValue() )) {
switch(CommandType.fromString( params.get(0).toString() )) {
case UserCommand:
processUserMessage(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), UserMessage.class));
processUserMessage(playerId, AMFMapper.deobfuscate(params.subList(1, params.size()), UserMessage.class));
break;
case SetLocation:
setPlayerLocation(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), SetLocationMessage.class));
setPlayerLocation(playerId, AMFMapper.deobfuscate(params.subList(1, params.size()), SetLocationMessage.class));
break;
case SetUserAvatarState:
setPlayerAvatarState(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), SetPlayerAvatarState.class));
setPlayerAvatarState(playerId, AMFMapper.deobfuscate(params.subList(1, params.size()), SetPlayerAvatarState.class));
break;
case SetUserAvatarPosition:
setPlayerAvatarPosition(playerId, AMFDeserializer.deserialize(params.subList(1, params.size()), SetPlayerAvatarPosition.class));
setPlayerAvatarPosition(playerId, AMFMapper.deobfuscate(params.subList(1, params.size()), SetPlayerAvatarPosition.class));
break;
default:
log.warn("GameServer.onMessage() unknown command: {}", params.get(0));
@ -74,109 +112,401 @@ public class GameServer {
}
}
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());
private void setPlayerAvatarPosition(int playerId, SetPlayerAvatarPosition message) {
if( message.getCoordinates() != null ) {
players.get(playerId).setX(message.getCoordinates().get("x").getDouble());
players.get(playerId).setY(message.getCoordinates().containsKey("y") ? message.getCoordinates().get("y").getDouble() : -100);
}
this.sendInPlayersLocation(playerId, CommandType.SetUserAvatarPosition,
new SetPlayerPosition(
playerId,
new Point((Double) message.getCoordinates().get("x").getValue(), (Double) message.getCoordinates().get("y").getValue()),
new Point(players.get(playerId).getX(), players.get(playerId).getY()),
message.getTweenerId().longValue()
)
);
}
private void setPlayerAvatarState(long playerId, SetPlayerAvatarState message) {
private void setPlayerAvatarState(int 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 {
private void processUserMessage(int playerId, UserMessage message) throws JsonProcessingException {
log.info("GameServer.processUserMessage() message: {}", message);
switch (UserCommandType.fromString(message.getCommandType())) {
case GetUserInitData: // todo: add more info about user (see decompiled sources)
String r = new XmlMapper().registerModule(new JavaTimeModule()).writeValueAsString(users.getUserInitInfoByUserId(playerId));
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
}
case UserFriendsGet, GetOnlineUserFriends -> this.sendResult(playerId, message.getTransactionId(), users.getFriendsOfUser(playerId, players));
case UserFriendsRequests -> this.sendResult(playerId, message.getTransactionId(), users.getRequestsOfUser(playerId, players));
case RevokeUserFriendship -> {
users.removeFriendshipWithUser(playerId, message.getArguments().get(0).getInt());
this.call(message.getArguments().get(0).getInt(), CommandType.OnFriendsRemoved, playerId);
}
case ApplyUserFriendship -> this.applyUserFriendship(playerId, message.getArguments().get(0).toString(), message.getArguments().get(1).toString());
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();
case GetFriendPanelData -> this.sendResult(playerId, message.getTransactionId(), "");
case UpdateUserData -> this.sendResult(playerId, message.getTransactionId(), null);
case GetUserLocation -> {
double prevLocation = message.getArguments().get(2).getDouble();
if (prevLocation == 0.0d) {
this.sendResult(playerId,
message.getTransactionId(),
new XmlMapper().writeValueAsString(
xmlMapper.writeValueAsString(
locationService.getDefaultLocation()
)
).replace("&lt;", "<")
);
return;
}
break;
case ChatMessage:
String text = (String) message.getArguments().get(1).getValue();
long requestedLocation = message.getArguments().get(1).getLong();
if( requestedLocation == -1L ) {
int homePlayerId = message.getArguments().get(0).getInt();
log.info("HOME: {}", xmlMapper.writeValueAsString(locationService.getHomeByUserId(homePlayerId)).replace("&lt;", "<"));
this.sendResult(playerId, message.getTransactionId(), xmlMapper.writeValueAsString(locationService.getHomeByUserId(homePlayerId)).replace("&lt;", "<"));
return;
}
if( requestedLocation == -2L ) {
return;
}
this.sendResult(playerId, message.getTransactionId(), xmlMapper.writeValueAsString(locationService.getLocationById(requestedLocation)).replace("&lt;", "<"));
}
case GetUserLocationById -> {
long nextLocation = message.getArguments().get(1).getLong();
if (nextLocation == -1) {
nextLocation = 0;
}
this.sendResult(playerId, message.getTransactionId(), xmlMapper.writeValueAsString(locationService.getLocationById(nextLocation)).replace("&lt;", "<"));
}
case GetCatalogInfo -> {
long catalogObjectId = message.getArguments().get(0).getLong();
// todo: implement
}
case ChatMessage -> {
String text = message.getArguments().get(1).toString();
sendInPlayersLocation(playerId, CommandType.ChatMessage, new ChatMessage(playerId, text));
break;
case Shoot:
}
case Shoot -> {
if (message.getSrv().equals("ROOM")) {
double x = (double) message.getArguments().get(1).getValue();
double y = (double) message.getArguments().get(2).getValue();
double x = message.getArguments().get(1).getDouble();
double y = message.getArguments().get(2).getDouble();
sendInPlayersLocation(playerId, CommandType.Shoot, new Shoot(playerId, x, y));
break;
}
this.sendInPlayersLocation(playerId, CommandType.SetUserAvatarState,
new SetPlayerState(playerId, players.get(playerId).getState())
);
break;
case GetUserInfo:
getUserInfo(playerId, message);
break;
this.users.setWeaponsCount(playerId, this.users.getIntegerUserProperty(playerId, PlayerProperties.WeaponsCount, 15) - 1);
}
case GetUserInfo -> getUserInfo(playerId, message.getArguments().get(0).getInt(), message);
case GetUserAvatar -> getAvatar(playerId, message);
case SaveUserAvatarChanges -> saveAvatar(playerId, message);
case GetUserUnlocks -> this.sendResult(playerId, message.getTransactionId(), "123");
case GetSnInvitePanelData -> {}
case GetGrantBlocks -> {}
case UseMagicAbility -> this.sendInPlayersLocation(playerId, CommandType.UseMagicAbility, new UseMagicAbility(
message.getArguments().get(0).getInt(),
message.getArguments().get(1).getInt()
));
case SetDefaultUserPhone -> {
long phoneId = message.getArguments().get(0).getLong();
this.users.setDefaultPhone(playerId, phoneId);
}
case SetUserBackground -> {
long bgId = message.getArguments().get(0).getLong();
this.users.setDefaultBackground(playerId, bgId);
}
case QueryUserFriendship -> {
int participantId = message.getArguments().get(0).getInt();
relationshipService.sendRequest(playerId, participantId);
this.call(participantId, CommandType.OnFriendshipRequestAdded,
new OneFR(
new UserFriend(playerId, players.get(playerId).getUsername(), players.get(playerId).getUsername(), true)
)
);
}
case GetPhoneBalance -> {
Integer balance = users.getUserAccountByUserId(playerId).getPhoneCardBalance();
this.sendResult(playerId, message.getTransactionId(), balance);
}
case PhoneMessage -> {
int receiverId = message.getArguments().get(0).getInt();
if (receiverId <= 0) return;
String messageText = message.getArguments().get(1).toString();
PhoneMessage pm = new PhoneMessage();
pm.setText(messageText);
pm.setSenderId(playerId);
pm.setReceiverId(receiverId);
pm.setIsNew(true);
pm.setSenderName(players.get(playerId).getUsername());
pm.setDateSent("");
phoneMessageService.savePhoneMessage(pm);
this.call(receiverId, CommandType.AddNewPhoneMessage, xmlMapper.writeValueAsString(pm));
}
case MarkPhoneMessageAsRead -> {
Long messageId = message.getArguments().get(0).getLong();
phoneMessageService.markAsRead(messageId);
}
case DeletePhoneMessage -> {
long messageId1 = message.getArguments().get(0).getLong();
phoneMessageService.removeById(messageId1);
}
case CardMessage -> {
if( !subtractUsualTickets(playerId, 20) ) return;
int receiverId = message.getArguments().get(0).getInt();
int postcardId = message.getArguments().get(1).getInt();
Postcard postcard = new Postcard();
postcard.setIsNew(true);
postcard.setDateSent("");
postcard.setSenderId(playerId);
postcard.setReceiverId(receiverId);
postcard.setSenderName(players.get(playerId).getUsername());
postcard.setCardId(postcardId);
postcardService.savePostcard(postcard);
this.call(receiverId, CommandType.CardMessage, xmlMapper.writeValueAsString(postcard));
}
case MarkCardMessageAsRead -> {
long postcardMessageId = message.getArguments().get(0).getLong();
this.postcardService.markAsRead(postcardMessageId);
}
case DeleteCardMessage -> {
long postcardMessageId = message.getArguments().get(0).getLong();
this.postcardService.removeById(postcardMessageId);
}
case BuyBatch -> buySomething(playerId, message.getArguments().get(0), message);
case LockHouse -> lockSomething(playerId, message.getArguments().get(0).getInt(), message.getArguments().get(1).getBoolean(), message);
case GetGame -> getGame(playerId, message.getArguments().get(0).getLong(), message.getTransactionId());
case GameScore -> processGameScore(playerId, message.getTransactionId(), message.getArguments().get(1).getInt());
case SendGameClose, GameStatistics -> {
this.sendResult(playerId, message.getTransactionId(), "0");
}
case RegisterGameWaiting -> {
Map<String, List<MultiplayerMinigameWaiting.Players>> m = new HashMap<>();
List<MultiplayerMinigameWaiting.Players> players1 = new ArrayList<>();
players1.add(new MultiplayerMinigameWaiting.Players(2, "jerk"));
m.put("0", players1);
this.call(playerId, CommandType.UpdateRoomTeam, new MultiplayerMinigameWaiting(m, 1, false));
players1.add(new MultiplayerMinigameWaiting.Players(3, "dullard"));
m.put("0", players1);
this.call(playerId, CommandType.UpdateRoomTeam, new MultiplayerMinigameWaiting(m, 1, false));
this.call(playerId, CommandType.LaunchRoomSession, new MultiplayerMinigameLaunch(m, "222"));
this.call(playerId, CommandType.MiniGameAction, new MiniGameAction("onAddUser", 1, "3"));
this.call(playerId, CommandType.MiniGameAction, new MiniGameAction("DisplayAvatar", 1, "3"));
this.call(playerId, CommandType.MiniGameAction, new MiniGameAction("onAddUser", 1, "2"));
this.call(playerId, CommandType.MiniGameAction, new MiniGameAction("DisplayAvatar", 1, "2"));
log.info("Players: {}", players);
//this.call(playerId, CommandType.MiniGameAction, new MiniGameAction("OnReady", 0, "2"));
//this.call(playerId, CommandType.MiniGameAction, new MiniGameAction("OnReady", 0, "3"));
}
case GetUserHomeLocationData -> {
String xs = xmlMapper.writeValueAsString(
new HomeStuff(
this.homeInventoryService.getHomeInventoryOfUser(playerId),
List.of(new HomeLocation(102, 2, 102L, 54, 708, 0, true, false, true, true, false, ClubAccessType.OPEN, 0, 0, 0.0, 0.0, 0, 0, true, true, true, true))
)
);
log.info("Output: {}", xs);
this.sendResult(playerId, message.getTransactionId(), xs);
}
case SaveLocationChanges -> {
if( message.getArguments().size() != 3 ) return;
int type = message.getArguments().get(1).getInt();
if( type == -2 ) { // home
Map<String, AMFObject> info = (Map<String, AMFObject>) message.getArguments().get(2).getRaw();
if( info.containsKey("Add") ) {
Map<String, AMFObject> additions = (Map<String, AMFObject>) info.get("Add").getRaw();
this.homeInventoryService.addFurnitureToCurrentHome(playerId, additions);
}
if( info.containsKey("Changes") ) {
Map<String, AMFObject> changes = (Map<String, AMFObject>) info.get("Changes").getRaw();
this.homeInventoryService.addFurnitureToCurrentHome(playerId, changes);
}
if( info.containsKey("Remove") ) {
Map<String, Object> remove = (Map<String, Object>) info.get("Remove").getRaw();
this.homeInventoryService.removeFurnitureFromHome(playerId, remove.keySet());
}
return;
}
// club
}
}
}
// todo: add more info about user (see decompiled sources)
private void getUserInfo(long playerId, UserMessage message) throws JsonProcessingException {
String r = new XmlMapper().registerModule(new JavaTimeModule()).writeValueAsString(users.getUserInfoByUserId(playerId));
private void processGameScore(int playerId, double transactionId, int amount) {
this.addUsualTickets(playerId, amount);
this.sendResult(playerId, transactionId, "");
}
private void getGame(int playerId, long gameId, double transactionId) throws JsonProcessingException {
this.sendResult(playerId, transactionId, xmlMapper.writeValueAsString(miniGameService.findGameById(gameId).get()).replace("&lt;", "<"));
}
private void lockSomething(int playerId, int what2Lock, Boolean state, UserMessage message) {
if( what2Lock == -2 ) {
this.users.pushUserProperty(playerId, PlayerProperties.IsClubLocked, state);
} else {
this.users.pushUserProperty(playerId, PlayerProperties.IsHomeLocked, state);
}
this.sendResult(playerId, message.getTransactionId(), state);
}
private void buySomething(int playerId, AMFObject obj, UserMessage message) {
List<AMFObject> array = (List<AMFObject>) obj.getRaw();
array.forEach(i -> this.buyOne(playerId, i, message));
}
private void buyOne(int playerId, AMFObject item, UserMessage message) {
Map<String, AMFObject> obj = (Map<String, AMFObject>) item.getRaw();
obj = (Map<String, AMFObject>) obj.get("item").getRaw();
long goodId = obj.get("id").getLong();
Optional<Good> tGood = this.goodsService.findById(goodId);
if( tGood.isEmpty() ) {
this.sendResult(playerId, message.getTransactionId(), new BuyGoodResult(new ArrayList<>()));
return;
}
Good good = tGood.get();
boolean isMagic = good.getMagicTickets() != 0;
AvatarInventoryType invType = AvatarInventoryType.fromGoodType(good.getGoodTypeId());
if( isMagic ) {
if( !subtractMagicTickets(playerId, good.getMagicTickets()) ) {
this.sendResult(playerId, message.getTransactionId(), new BuyGoodResult(new ArrayList<>()));
return;
}
this.users.pushToInventory(playerId, invType, goodId);
this.sendResult(playerId, message.getTransactionId(), new BuyGoodResultGood(new BuyGoodResultGood.BuyGoodBody(false, new ArrayList<>())));
return;
}
if( !subtractUsualTickets(playerId, good.getUsualTickets()) ) {
this.sendResult(playerId, message.getTransactionId(), new BuyGoodResult(new ArrayList<>()));
return;
}
this.users.pushToInventory(playerId, invType, goodId);
this.sendResult(playerId, message.getTransactionId(), new BuyGoodResultGood(new BuyGoodResultGood.BuyGoodBody(false, new ArrayList<>())));
}
private void addUsualTickets(int userId, int amount) {
int val = this.users.getUsualTickets(userId);
val += amount;
this.users.setUsualTickets(userId, val);
this.call(userId, CommandType.UpdateTickets, new UpdateTickets(val, this.users.getMagicTickets(userId)));
}
private boolean subtractUsualTickets(int userId, int amount) {
int val = this.users.getUsualTickets(userId);
if ( val >= amount ) {
val -= amount;
this.users.setUsualTickets(userId, val);
this.call(userId, CommandType.UpdateTickets, new UpdateTickets(val, this.users.getMagicTickets(userId)));
return true;
}
return false;
}
private boolean subtractMagicTickets(int userId, int amount) {
int val = this.users.getMagicTickets(userId);
if ( val >= amount ) {
val -= amount;
this.users.setMagicTickets(userId, val);
this.call(userId, CommandType.UpdateTickets, new UpdateTickets(this.users.getUsualTickets(userId), val));
return true;
}
return false;
}
private void applyUserFriendship(Integer userId, String acceptString, String denyString) {
List<Integer> accepted = Arrays.stream(acceptString.split(","))
.filter(s -> !s.isEmpty())
.map(Integer::parseInt)
.collect(Collectors.toList());
List<Integer> denied = Arrays.stream(denyString.split(","))
.filter(s -> !s.isEmpty())
.map(Integer::parseInt)
.collect(Collectors.toList());
users.acceptFriendshipWithUsers(userId, accepted);
users.denyFriendshipsWithUsers(userId, denied);
Map<String, UserFriend> m = new HashMap<>();
m.put("1", new UserFriend(userId, "", players.get(userId).getUsername(), true));
accepted.forEach(uid -> this.call(uid, CommandType.OnFriendsAdded, m));
}
private void saveAvatar(int playerId, UserMessage message) {
Map<String, AMFObject> changes = (Map<String, AMFObject>) message.getArguments().get(0).getRaw();
List<AMFObject> bodyParts = (List<AMFObject>) changes.get("BodyParts").getRaw();
List<AMFObject> inventory = (List<AMFObject>) changes.get("Inventory").getRaw();
List<Triplet<Long, Object, AvatarInventoryType>> l = Stream.concat(
bodyParts.stream().map(f -> (Map<String, AMFObject>) f.getRaw()).map(f -> Triplet.with(f.get("Id").getLong(), f.get("Color").getRaw(), AvatarInventoryType.BodyParts)),
inventory.stream().map(f -> (Map<String, AMFObject>) f.getRaw()).map(f -> Triplet.with(f.get("Id").getLong(), f.get("Color").getRaw(), AvatarInventoryType.fromGoodId(goodsService, f.get("Id").getLong())))
).collect(Collectors.toList());
users.resetUsedClothes(playerId);
for(var i: l) {
var s = String.valueOf(i.getValue1());
int color = 0;
if( !s.equals("NaN") ) {
color = ((Double) i.getValue1()).intValue();
}
users.setDefaultInventoryItem(playerId, i.getValue0(), i.getValue2(), color);
}
this.sendResult(playerId, message.getTransactionId(), new ArrayList<>());
this.updateLocationPlayers(playerId, this.players.get(playerId).getLocationId());
}
private void getAvatar(int playerId, UserMessage message) throws JsonProcessingException {
String r = xmlMapper.writeValueAsString(users.getUserAvatarByUserId(playerId));
r = r.substring(13);
r = r.substring(0, r.length() - 14);
this.sendResult(playerId, message.getTransactionId(), r);
}
private void setPlayerLocation(long playerId, SetLocationMessage message) {
private void getUserInfo(int playerId, int targetId, UserMessage message) throws JsonProcessingException {
String r = xmlMapper.writeValueAsString(new GetUserInfo(users.getUserInfoByUserId(targetId, false, playerId), users.getOtherUserAvatar(targetId)));
r = r.substring(11);
r = r.substring(0, r.length()-12);
this.sendResult(playerId, message.getTransactionId(), r);
}
private void setPlayerLocation(int playerId, SetLocationMessage message) {
Player p = this.players.get(playerId);
this.deleteSelf(playerId, p.getLocationId());
int prevLocation = p.getLocationId();
long 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.setX(message.getCoordinates().get("x").getDouble());
p.setY(message.getCoordinates().get("y").getDouble());
p.setState(message.getStartState());
this.updateLocationPlayers(playerId, prevLocation);
this.sendResult(playerId, message.getTransactionId(), "");
}
private void deleteSelf(long playerId, int locationId) {
private void deleteSelf(int playerId, long locationId) {
Player p = this.players.get(playerId);
this.sendInLocation(locationId, CommandType.RemoveUserFromLocation, playerId);
}
private void updateLocationPlayers(long playerId, int prevLocation) {
int locationId = this.players.get(playerId).getLocationId();
private void updateLocationPlayers(int playerId, long prevLocation) {
long locationId = this.players.get(playerId).getLocationId();
this.sendInLocation(prevLocation, CommandType.RemoveUserFromLocation, playerId);
for( int i = 0; i < 5; i++ ) {
for( int i = 0; i < 3; i++ ) {
try {
Thread.sleep(300);
this.sendInPlayersLocation(playerId, CommandType.AddUserToLocation, new AddUserToLocation(
playerId,
users.getAvatarById(playerId, this.players.get(playerId))
));
} catch (InterruptedException ie) {
log.error("Sleep exception: {}", ie.getMessage());
}
}
this.players.keySet().forEach(pid -> {
Player p = this.players.get(pid);
@ -192,26 +522,27 @@ public class GameServer {
});
}
private void sendInPlayersLocation(long playerId, CommandType type, Object obj) {
this.sendInLocation(players.get(playerId).getLocationId(), type, obj);
private void sendInPlayersLocation(int playerId, CommandType type, Object obj) {
Player player = this.players.get(playerId);
this.sendInLocation(player.getLocationId(), type, obj);
}
private void sendInLocation(int locationId, CommandType type, Object obj) {
private void sendInLocation(long 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) {
private void sendResult(int playerId, double tid, Object obj) {
this.sendMessage(playerId, new CallMessage("_result", tid, null, obj));
}
private void call(long playerId, CommandType function, Object obj) {
private void call(int playerId, CommandType function, Object obj) {
this.sendMessage(playerId, new CallMessage(function.getValue(), 0d, null, obj));
}
private void sendMessage(long playerId, Object obj) {
private void sendMessage(int playerId, Object obj) {
try {
this.players.get(playerId)
.getConnection()
@ -221,10 +552,14 @@ public class GameServer {
}
}
public void onDisconnect(long playerId) {
public void onDisconnect(int 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);
}
public int getPlayersCount() {
return this.players.size();
}
}

View File

@ -0,0 +1,74 @@
package com.alterdekim.game.component;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
public class NativeDao {
@Autowired
EntityManager em;
/*
This component itself is a big security breach due to straightforward pushing changes into the
database from the http requests of the user (even though the user is always admin).
The application may be vulnerable to SQL injections and some other stuff.
I understand that, but due to limit of time I have, I decided to leave it as is.
It's my hobby project, not an enterprise-grade server.
*/
@Transactional
public void updateTable(String table, String column, Boolean val, Long id) {
String s = "UPDATE %s t SET t.%s = %b WHERE t.id = %d";
String sql = String.format(s, table, camelToSnake(column), val, id);
em.createNativeQuery(sql).executeUpdate();
}
@Transactional
public void insertEntity(String table, Map<String, String> vals) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
sb.append("INSERT INTO ");
sb.append(table);
sb.append(" (");
Iterator<String> i = vals.keySet().iterator();
while( i.hasNext() ) {
String key = i.next();
sb.append(camelToSnake(key));
sb2.append(vals.get(key));
if( !i.hasNext() ) break;
sb.append(", ");
sb2.append(", ");
}
sb.append(") VALUES (");
sb.append(sb2);
sb.append(")");
log.info("Query: {}", sb);
em.createNativeQuery(sb.toString()).executeUpdate();
}
private String camelToSnake(String str) {
String result = "";
char c = str.charAt(0);
result = result + Character.toLowerCase(c);
for (int i = 1; i < str.length(); i++) {
char ch = str.charAt(i);
if (Character.isUpperCase(ch)) {
result = result + '_';
result
= result
+ Character.toLowerCase(ch);
} else {
result = result + ch;
}
}
return result;
}
}

View File

@ -0,0 +1,20 @@
package com.alterdekim.game.component;
import com.alterdekim.game.repository.OnlineStatusRepository;
import com.alterdekim.game.service.OnlineStatusService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class OnlineChecker {
@Autowired
private OnlineStatusService statusService;
@Scheduled(fixedRate = 2000)
private void checker() {
long secs = (System.currentTimeMillis() / 1000L) - 20;
statusService.listPingsOlderThan(secs).forEach(o -> statusService.delete(o));
}
}

View File

@ -13,6 +13,7 @@ import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class RTMPListener extends Thread {
@ -29,7 +30,7 @@ public class RTMPListener extends Thread {
private ConnectionState connectionState;
private final Map<ConnectionState, ConnectionProcessor> connectionProcessors = new HashMap<>();
private final Map<ConnectionState, ConnectionProcessor> connectionProcessors = new ConcurrentHashMap<>();
public RTMPListener(Socket sock, RTMPServer parent, Integer uid, GameServer gameServer) {
try {

View File

@ -0,0 +1,16 @@
package com.alterdekim.game.component;
import com.alterdekim.game.entity.User;
import com.alterdekim.game.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ReferenceLoader {
@Autowired
private UserRepository userRepository;
public User getUserReference(Integer userId) {
return userRepository.getReferenceById(userId);
}
}

View File

@ -9,19 +9,17 @@ import com.alterdekim.flash.decompiler.tag.DoAction;
import com.alterdekim.flash.decompiler.tag.TagType;
import com.alterdekim.flash.decompiler.translator.Flash2Java;
import com.alterdekim.flash.decompiler.translator.Java2Flash;
import com.alterdekim.game.component.game.BodyPartType;
import com.alterdekim.game.component.game.avatar.BodyPartType;
import com.alterdekim.game.config.ServerConfig;
import com.alterdekim.game.entity.*;
import com.alterdekim.game.repository.BodyPartRepository;
import com.alterdekim.game.repository.SmileRepository;
import com.alterdekim.game.service.*;
import com.alterdekim.game.storage.StorageProperties;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.javatuples.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import java.io.File;
@ -37,6 +35,9 @@ public class StartUpListener {
private static final String ADMIN_USERNAME = "admin";
@Getter
private long startTime;
@Autowired
private ServerConfig config;
@ -136,10 +137,13 @@ public class StartUpListener {
@Autowired
private PromotionBannerService promotionBannerService;
@Autowired
private MiniGameService miniGameService;
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
this.startTime = System.currentTimeMillis();
// todo: compile other swf's
if( userService.findByUsername(ADMIN_USERNAME) != null ) {
// todo: remove hardcoded cache folder
@ -164,14 +168,12 @@ public class StartUpListener {
if( userService.findByUsername(ADMIN_USERNAME) != null ) return;
String pwd = UUID.randomUUID().toString();
log.info("Your admin account password is: {}\nChange it later.", pwd);
userService.saveUser(ADMIN_USERNAME, pwd);
userService.saveUser(ADMIN_USERNAME, pwd, Role.RoleType.RoleAdmin);
log.info("Moving pre-compiled data to our database.");
try {
processResources(storageProperties.getLocation() + File.separator + config.getDefaultResourcesPath());
processBase(storageProperties.getLocation() + File.separator + config.getDefaultBasePath());
// todo: implements miniquests
String miniquests = storageProperties.getLocation() + File.separator + config.getDefaultMiniquestsPath();
processCatalogs(storageProperties.getLocation() + File.separator + config.getDefaultCatalogsPath());
} catch (IOException e) {
log.error("Unable to move pre-compiled data to the server's database: {}", e.getMessage());
@ -183,9 +185,53 @@ public class StartUpListener {
pushBodyParts();
pushLocations();
pushLocationObjects();
pushMiniGames();
pushHouseLocations();
pushPhoneSkins();
log.info("Initialization complete");
}
private void pushMiniGames() {
miniGameService.save(new MiniGame(0L, "Рентген", 0, 0, 4250, 1d, 2, true, true, false, 0L, 0L, "1", "", ""));
miniGameService.save(new MiniGame(1L, "Дары леса", 10120, 1291, 1749, 10d, 1, true, false, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(2L, "Катер", 10089, 516, 4265, 100d, 1, true, true, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(3L, "Волейбол", 10087, 513, 301, 100d, 1, true, true, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(4L, "Кафе", 10088, 515, 310, 1d, 0, true, true, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(5L, "Труба", 10084, 1104, 11763, 1d, 0, false, true, true, 0L, 0L, "1", "", ""));
miniGameService.save(new MiniGame(6L, "Секретики", 10097, 806, 763, 1d, 0, true, false, true, 1000L, 10000L, "1", "", "<Groups><item ID=\"0\" MaxUsersCount=\"2\" MinUsersCount=\"2\" /></Groups>"));
miniGameService.save(new MiniGame(7L, "Смешарики", 10086, 510, 3126, 1d, 1, true, true, true, 1000L, 10000L, "0", "", "<Groups><item ID=\"0\" MaxUsersCount=\"2\" MinUsersCount=\"2\" /></Groups>"));
miniGameService.save(new MiniGame(8L, "Модельер", 10101, 948, 4300, 5d, 0, false, false, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(9L, "Горки", 10095, 557, 341, 40d, 1, true, true, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(10L, "Скачки", 10093, 518, 319, 1d, 0, true, true, true, 1000L, 10000L, "0", "", "<Groups><item ID=\"0\" MaxUsersCount=\"2\" MinUsersCount=\"2\" /></Groups>"));
miniGameService.save(new MiniGame(11L, "Футбол", 10112, 1212, 4247, 1d, 3, true, true, true, 1000L, 30000L, "0", "", ""));
miniGameService.save(new MiniGame(12L, "Няня", 10083, 505, 4241, 30d, 0, false, true, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(13L, "Двигатель", 10094, 519, 322, 5d, 0, false, true, true, 0L, 0L, "0", "", ""));
miniGameService.save(new MiniGame(14L, "Шарабудка", 8054, 3218, 1127, 1d, 0, false, true, true, 0L, 0L, "1", "", ""));
miniGameService.save(new MiniGame(92L, "Трасса", 0, 0, 4267, 1d, 1, false, false, true, 0L, 0L, "1", "", ""));
miniGameService.save(new MiniGame(206L, "Муравей", 2148, 2148, 3170, 1d, 0, true, false, true, 0L, 0L, "1", "", ""));
}
private void pushPhoneSkins() {
phoneIconService.findAll()
.stream()
.map(i -> Pair.with(i.getId(), mrService.findById(i.getIconMRId().longValue())))
.filter(i -> i.getValue1().isPresent())
.map(i -> Pair.with(i.getValue0(), i.getValue1().get()))
.filter(i -> this.mrService.findByUrl(i.getValue1().getUrl().replace("-icon.swf", "-skin.swf"), 26).isPresent())
.forEach(i ->
this.phoneIconService.save(
new PhoneSkin(
i.getValue0(),
this.mrService.findByUrl(i.getValue1().getUrl().replace("-icon.swf", "-skin.swf"), 26).get().getId()
)
)
);
}
private void pushPromotionBanners() {
promotionBannerService.savePromotionBanner(new PromotionBanner(9841, true));
promotionBannerService.savePromotionBanner(new PromotionBanner(9955, true));
@ -204,8 +250,155 @@ public class StartUpListener {
preloaderService.savePreloader(new Preloader(11994, 2000, true));
}
private void pushLocationObjects() {
locationService.addObject(new LocationObjectInstance(2, 23, 0, 1045L, 9L, 445.0d, 50.0, "", "ТП на главную площадь (Смешмаг)"));
locationService.addObject(new LocationObjectInstance(3, 7, 0, 1068L, 24L, 675.0d, 260.0, "", "Стол \"Смешарики\" (ППД)"));
locationService.addObject(new LocationObjectInstance(3, 7, 0, 1069L, 24L, 670.0d, 330.0, "", "Стол \"Смешарики\" (ППД)"));
locationService.addObject(new LocationObjectInstance(4, 0, 4, 1243L, 24L, 24.0d, 72.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Зимняя лавка помидоров от копатыча (ППД)"));
locationService.addObject(new LocationObjectInstance(4, 0, 9, 4316L, 24L, 560.0d, 360.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Правила игры в \"Смешарики\" (ППД)"));
locationService.addObject(new LocationObjectInstance(2, 32, 0, 1073L, 24L, 595.0d, 150.0, "", "ТП в Диско (ППД)"));
locationService.addObject(new LocationObjectInstance(2, 45, 0, 7861L, 24L, 405.0d, 130.0, "", "ТП в Лес (ППД)"));
locationService.addObject(new LocationObjectInstance(2, 53, 0, 7877L, 24L, 30.0d, 200.0, "", "ТП в Порт (ППД)"));
locationService.addObject(new LocationObjectInstance(2, 22, 0, 228L, 24L, 160.0d, 130.0, "", "ТП в Парк (ППД)"));
locationService.addObject(new LocationObjectInstance(2, 47, 0, 7849L, 23L, 620.0d, 215.0, "", "ТП на Площадь у Больнички (Главная площадь)"));
locationService.addObject(new LocationObjectInstance(2, 53, 0, 7850L, 23L, 35.0d, 220.0, "", "ТП в Порт (Главная Площадь)"));
locationService.addObject(new LocationObjectInstance(2, 10, 0, 1038L, 23L, 127.0d, 47.0, "", "ТП в Детский Сад (Главная Площадь)"));
locationService.addObject(new LocationObjectInstance(2, 9, 0, 1039L, 23L, 358.0d, 37.0, "", "ТП в Смешмаг (Главная Площадь)"));
locationService.addObject(new LocationObjectInstance(2, 40, 0, 1040L, 23L, 548.0d, 50.0, "", "ТП в Дом Мод (Главная Площадь)"));
locationService.addObject(new LocationObjectInstance(2, 23, 0, 216L, 10L, 705.0d, 200.0, "", "ТП на Главную Площадь (Детский Сад)"));
locationService.addObject(new LocationObjectInstance(2, 23, 0, 1054L, 40L, 20.0d, 175.0, "", "ТП на Главную Площадь (Дом Мод)"));
locationService.addObject(new LocationObjectInstance(2, 38, 0, 7869L, 45L, 55.0d, 170.0, "", "ТП в Ромашковую Долину (Лес)"));
locationService.addObject(new LocationObjectInstance(2, 24, 0, 7870L, 45L, 680.0d, 170.0, "", "ТП на ППД (Лес)"));
locationService.addObject(new LocationObjectInstance(2, 24, 0, 286L, 32L, 123.0d, 70.0, "", "ТП на ПДД (Диско)"));
locationService.addObject(new LocationObjectInstance(2, 47, 0, 7853L, 68L, 670.0d, 230.0, "", "ТП на Площадь у Больнички (Сити)"));
locationService.addObject(new LocationObjectInstance(2, 71, 0, 2158L, 68L, 443.0d, 133.0, "", "ТП в Автосалон (Сити)"));
locationService.addObject(new LocationObjectInstance(2, 0, 0, 3587L, 68L, 150.0d, 330.0, "", "ТП в Пещеру (Сити)"));
locationService.addObject(new LocationObjectInstance(2, 67, 0, 1936L, 68L, 155.0d, 130.0, "", "ТП в Корпорацию Клубов (Сити)"));
locationService.addObject(new LocationObjectInstance(2, 61, 0, 1946L, 68L, 645.0d, 170.0, "", "ТП в Бюро Путешествий (Сити)"));
locationService.addObject(new LocationObjectInstance(2, 68, 0, 2159L, 71L, 307.0d, 63.0, "", "ТП в Сити (Автосалон)"));
locationService.addObject(new LocationObjectInstance(2, 68, 0, 1619L, 61L, 630.0d, 270.0, "", "ТП в Сити (Бюро Путешествий)"));
locationService.addObject(new LocationObjectInstance(2, 68, 0, 2037L, 67L, 425.0d, 35.0, "", "ТП в Сити (Корпорация Клубов)"));
locationService.addObject(new LocationObjectInstance(2, 68, 0, 7855L, 47L, 420.0d, 150.0, "", "ТП в Сити (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(2, 31, 0, 7857L, 47L, 200.0d, 217.0, "", "ТП на Снежную гору (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(2, 23, 0, 7860L, 47L, 526.0d, 362.0, "", "ТП на Главную Площадь (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(2, 49, 0, 1105L, 47L, 595.0d, 190.0, "", "ТП в Больничку (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(2, 63, 0, 2317L, 47L, 211.0d, 18.0, "", "ТП в Школу Магов (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(2, 47, 0, 443L, 49L, 655.0d, -35.0, "", "ТП на Площадь у Больнички (Больничка)"));
locationService.addObject(new LocationObjectInstance(2, 47, 0, 1752L, 63L, 300.0d, 50.0, "", "ТП на Площадь у Больнички (Школа Магов)"));
locationService.addObject(new LocationObjectInstance(2, 176, 0, 3852L, 47L, 515.0d, 160.0, "", "ТП на Почту (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(2, 47, 0, 3379L, 176L, -10.0d, 150.0, "", "ТП на Площадь у Больнички (Почта)"));
locationService.addObject(new LocationObjectInstance(2, 24, 0, 4L, 22L, 310.0d, 140.0, "", "ТП на ППД (Парк)"));
locationService.addObject(new LocationObjectInstance(2, 27, 0, 267L, 22L, 670.0d, 181.0, "", "ТП на Пляж (Парк)"));
locationService.addObject(new LocationObjectInstance(2, 24, 0, 7876L, 53L, 20.0d, 330.0, "", "ТП на ППД (Морской порт)"));
locationService.addObject(new LocationObjectInstance(2, 23, 0, 749L, 53L, 650.0d, 360.0, "", "ТП на Главную Площадь (Морской порт)"));
locationService.addObject(new LocationObjectInstance(2, 45, 0, 7873L, 38L, 685.0d, 260.0, "", "ТП в Лес (Ромашковая Долина)"));
locationService.addObject(new LocationObjectInstance(2, 29, 0, 7874L, 38L, 25.0d, 260.0, "", "ТП в Автодром (Ромашковая Долина)"));
locationService.addObject(new LocationObjectInstance(2, 38, 0, 7863L, 29L, 630.0d, 320.0, "", "ТП в Ромашковую Долину (Автодром)"));
locationService.addObject(new LocationObjectInstance(2, 27, 0, 7866L, 29L, 50.0d, 280.0, "", "ТП на Пляж (Автодром)"));
locationService.addObject(new LocationObjectInstance(3, 1, 0, 1748L, 45L, 570.0d, 265.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Дары Леса (Лес)"));
locationService.addObject(new LocationObjectInstance(22, 0, 0, 4313L, 9L, 700.0d, 411.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Модный журнал (Смешмаг)"));
locationService.addObject(new LocationObjectInstance(22, 1, 2, 6349L, 9L, 553.0d, 354.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Бот Эллис (Смешмаг)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 1043L, 10L, 220.0d, 300.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Крошки (Детский сад)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 1041L, 10L, 400.0d, 450.0, "", "Лошадка (Детский сад)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 1042L, 10L, 500.0d, 450.0, "", "Мячик (Детский сад)"));
locationService.addObject(new LocationObjectInstance(3, 12, 0, 291L, 10L, 286.0d, 83.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Поухаживай за крошками (Детский сад)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 344L, 40L, 700.0d, 411.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Стиляга (Дом Мод)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 6350L, 40L, 646.0d, 203.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Бот Стефан (Дом Мод)"));
locationService.addObject(new LocationObjectInstance(3, 8, 0, 986L, 40L, 333.0d, 80.0, "", "ТП в игру Студия Моды (Дом Мод)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 1052L, 40L, 691.0d, 61.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Правила (Дом Мод)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 1049L, 40L, 208.0d, 47.0, "", "Диван Жюри (Дом Мод)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 221L, 0L, 700.0d, 420.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Все для Крошки (Детский сад)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 309L, 0L, 700.0d, 360.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Возьми крошку себе (Детский сад)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 4851L, 67L, 625.0d, 370.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Бот Ба-босс (Корпорация клубов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 105, 1938L, 67L, 680.0d, 350.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Правила (Корпорация клубов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 1940L, 67L, 287.0d, 32.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Построй свой клуб (Корпорация клубов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 1944L, 67L, 515.0d, 48.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Пригласи артиста (Корпорация клубов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 5282L, 67L, 170.0d, 270.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Объекты на столе (Корпорация клубов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 157, 2161L, 71L, 670.0d, 390.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка За рулем (Автосалон)"));
locationService.addObject(new LocationObjectInstance(4, 0, 347, 2165L, 71L, 670.0d, 330.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Тюнинг (Автосалон)"));
locationService.addObject(new LocationObjectInstance(4, 0, 157, 3210L, 71L, 254.0d, 215.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Автомобиль (Автосалон)"));
locationService.addObject(new LocationObjectInstance(4, 0, 157, 2162L, 71L, 143.0d, 377.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Журнал За рулем (Автосалон)"));
locationService.addObject(new LocationObjectInstance(4, 0, 347, 2167L, 71L, 510.0d, 20.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Шкаф (Автосалон)"));
locationService.addObject(new LocationObjectInstance(4, 0, 347, 2164L, 71L, 613.0d, 245.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Журнал Тюнинг (Автосалон)"));
locationService.addObject(new LocationObjectInstance(3, 0, 0, 1621L, 61L, 122.0d, 176.0, "", "ТП в фотобудку (Бюро путешествий)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 4328L, 61L, 459.0d, 227.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка паспортов (Бюро путешествий)"));
locationService.addObject(new LocationObjectInstance(4, 0, 83, 1626L, 61L, 254.0d, 403.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Каталог стран (Бюро путешествий)"));
locationService.addObject(new LocationObjectInstance(4, 0, 83, 1649L, 61L, 280.0d, 219.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Каталог глобус (Бюро путешествий)"));
locationService.addObject(new LocationObjectInstance(4, 0, 83, 2985L, 61L, 690.0d, 380.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Вокруг света (Бюро путешествий)"));
locationService.addObject(new LocationObjectInstance(4, 0, 62, 393L, 47L, 123.0d, 317.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Витрина Шарафоны (Площадь у Больнички)"));
locationService.addObject(new LocationObjectInstance(4, 0, 15, 403L, 47L, 87.0d, 350.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Банкомат (Площадь у Больнички"));
locationService.addObject(new LocationObjectInstance(3, 0, 0, 4334L, 49L, 274.0d, 14.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП на Рентген (Больничка)"));
locationService.addObject(new LocationObjectInstance(4, 0, 18, 435L, 49L, 434.0d, 16.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Шкафа с вещами (Больничка)"));
locationService.addObject(new LocationObjectInstance(4, 0, 19, 4320L, 49L, 195.0d, 29.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Каталог Перевязки (Больничка)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 439L, 49L, 478.0d, 102.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Бот Бинтик (Больничка)"));
locationService.addObject(new LocationObjectInstance(4, 0, 19, 444L, 49L, 358.0d, 41.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Каталог с повязками (Больничка)"));
locationService.addObject(new LocationObjectInstance(3, 0, 0, 6267L, 63L, 193.0d, 100.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Игра Урок волшебного карандаша (Школа Магов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 4321L, 63L, 250.0d, 68.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Правила Урок волшебного карандаша (Школа Магов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 9846L, 63L, 180.0d, 380.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Бот Умникус (Школа Магов)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 6271L, 63L, 404.0d, 62.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Расписание уроков (Школа Магов)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 4005L, 176L, 569.0d, 318.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Отправь открытку другу (Почта)"));
locationService.addObject(new LocationObjectInstance(3, 10, 0, 1537L, 22L, 27.0d, 341.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Скачки (Парк)(Левые скачки)"));
locationService.addObject(new LocationObjectInstance(3, 10, 0, 1539L, 22L, 135.0d, 314.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Скачки (Парк)(Средние скачки)"));
locationService.addObject(new LocationObjectInstance(3, 10, 0, 1538L, 22L, 234.0d, 323.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Скачки (Парк)(Правые скачки)"));
locationService.addObject(new LocationObjectInstance(3, 9, 0, 2324L, 22L, 152.0d, 157.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Воздушные горки (Парк)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 4317L, 22L, 60.0d, 268.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Правила игры Скачки (Парк)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 4318L, 22L, 530.0d, 200.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Правила игры Футбол (Парк)"));
locationService.addObject(new LocationObjectInstance(3, 11, 0, 1567L, 22L, 470.0d, 160.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Футбол (Парк) (Левый вход)"));
locationService.addObject(new LocationObjectInstance(3, 11, 0, 1567L, 22L, 580.0d, 158.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Футбол (Парк) (Правый вход)"));
locationService.addObject(new LocationObjectInstance(3, 2, 0, 759L, 53L, 525.0d, 188.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Бешеный катер (Морской порт)"));
locationService.addObject(new LocationObjectInstance(4, 0, 26, 6440L, 53L, -31.0d, 88.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Дайвинг-центр (Морской порт)"));
locationService.addObject(new LocationObjectInstance(2, 0, 0, 865L, 53L, 640.0d, 270.0, "", "ТП в Подводный мир (Морской порт)"));
locationService.addObject(new LocationObjectInstance(3, 0, 0, 984L, 53L, 667.0d, 155.0, "", "Иконка Загляни под воду (Морской порт)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 751L, 53L, 112.0d, 200.0, "", "Баллоны (Морской порт)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 5408L, 53L, 634.0d, 365.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Иконка Дайв-инфо (Морской порт)"));
locationService.addObject(new LocationObjectInstance(3, 13, 0, 1101L, 38L, 554.0d, 130.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Вечный Двигатель (Ромашковая долина)(Дом Пина)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 6081L, 38L, 32.0d, 57.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в Домик Лосяша (Ромашковая Долина)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 2153L, 38L, 404.0d, 118.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в Домик Ёжика (Ромашковая долина)"));
locationService.addObject(new LocationObjectInstance(2, 0, 0, 2335L, 38L, 350.0d, 40.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в Домик Кроша (Ромашковая долина)"));
locationService.addObject(new LocationObjectInstance(2, 0, 0, 6838L, 38L, 170.0d, 120.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в Домик Нюши (Ромашковая долина)"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 1100L, 38L, 190.0d, 5.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в Домик Карыча (Ромашковая долина)"));
locationService.addObject(new LocationObjectInstance(3, 0, 0, 0L, 29L, 84.0d, 165.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП на Формулу Шарарама (Автодром)"));
locationService.addObject(new LocationObjectInstance(3, 5, 0, 1102L, 27L, 117.0d, 306.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП Смотри в трубу (Пляж)"));
locationService.addObject(new LocationObjectInstance(2, 29, 0, 7847L, 27L, 292.0d, 54.0, "", "ТП в Автодром (Пляж)"));
locationService.addObject(new LocationObjectInstance(3, 3, 0, 265L, 27L, 35.0d, 72.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Волейбол (Пляж)"));
locationService.addObject(new LocationObjectInstance(3, 4, 0, 311L, 27L, 530.0d, -30.0, "", "ТП в игру Кафе (Пляж)"));
locationService.addObject(new LocationObjectInstance(3, 6, 0, 761L, 27L, 97.0d, 158.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "ТП в игру Секретики (Пляж)"));
locationService.addObject(new LocationObjectInstance(2, 22, 0, 7848L, 27L, 686.0d, 225.0, "", "ТП в Парк (Пляж)"));
locationService.addObject(new LocationObjectInstance(4, 0, 0, 4315L, 27L, 53.0d, 164.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Правила игры Секретики (Пляж)"));
locationService.addObject(new LocationObjectInstance(3, 14, 0, 1099L, 38L, 40.0d, 200.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Шарабудка (Ромашковая долина)"));
locationService.addObject(new LocationObjectInstance(3, 0, 0, 3177L, 51L, 600.0d, 280.0, "", "Цветок в джунглях"));
locationService.addObject(new LocationObjectInstance(0, 0, 0, 3178L, 51L, 400.0d, 280.0, "<options><behaviour IsPositionHeld=\"1\" /></options>", "Фея джунглей"));
}
private void pushLocations() {
locationService.addLocation(new Location(47l, 3849l, 400.0d, 250.0d, "Площадь у больнички", true, true));
locationService.addLocation(new Location(47L, 3849L, 400.0d, 250.0d, "Площадь у больнички", false, true));
locationService.addLocation(new Location(45L, 3993L, 200.0d, 360.0d, "Дремучий лес", true, true));
locationService.addLocation(new Location(9L, 1035L, 350.0d, 330.0d, "Смешмаг", false, true));
locationService.addLocation(new Location(10L, 1031L, 530.0d, 280.0d, "Детский сад", false, true));
locationService.addLocation(new Location(22L, 3990L, 340.0d, 190.0d, "Парк", false, true));
locationService.addLocation(new Location(23L, 3992L, 300.0d, 380.0d, "Главная площадь", false, true));
locationService.addLocation(new Location(24L, 2422L, 380.0d, 240.0d, "ППД", false, true));
locationService.addLocation(new Location(26L, 1630L, 250.0d, 250.0d, "Египет", false, true));
locationService.addLocation(new Location(27L, 2413L, 660.0d, 240.0d, "Пляж лазурный", false, true));
locationService.addLocation(new Location(29L, 3996L, 300.0d, 270.0d, "Автодром", false, true));
locationService.addLocation(new Location(31L, 3999L, 360.0d, 310.0d, "Снежная гора", false, true));
locationService.addLocation(new Location(32L, 2424L, 200.0d, 190.0d, "Диско", false, true));
locationService.addLocation(new Location(38L, 1029L, 480.0d, 400.0d, "Ромашковая долина", false, true));
locationService.addLocation(new Location(40L, 2436L, 200.0d, 300.0d, "Дом мод", false, true));
locationService.addLocation(new Location(49L, 2411L, 370.0d, 350.0d, "Больничка", false, true));
locationService.addLocation(new Location(51L, 3164L, 250.0d, 350.0d, "Джунгли", false, true));
locationService.addLocation(new Location(53L, 3989L, 330.0d, 380.0d, "Порт", false, true));
locationService.addLocation(new Location(61L, 2415L, 710.0d, 340.0d, "Бюро путешествий", false, true));
locationService.addLocation(new Location(63L, 6266L, 380.0d, 150.0d, "Школа магов", false, true));
locationService.addLocation(new Location(67L, 2420L, 570.0d, 320.0d, "Корпорация клубов", false, true));
locationService.addLocation(new Location(68L, 3994L, 570.0d, 320.0d, "Сити", false, true));
locationService.addLocation(new Location(71L, 2421L, 300.0d, 125.0d, "Автосалон", false, true));
locationService.addLocation(new Location(176L, 4010L, 60.0d, 300.0d, "Почта", false, true));
locationService.addLocation(new Location(226L, 11945L, 370.0d, 370.0d, "Затерянный каньон", false, true));
}
private void pushHouseLocations() {
locationService.addHouseLocation(new HouseLocation(102L, 708, true));
}
private void pushBodyParts() {
@ -319,7 +512,6 @@ public class StartUpListener {
);
}
// todo: implement other stuff from base.swf
private void processBase(String swf) throws IOException {
log.info("Processing base");

View File

@ -1,55 +0,0 @@
package com.alterdekim.game.component.game;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDateTime;
@AllArgsConstructor
@Getter
public class AvatarInventoryItem {
@JacksonXmlProperty(localName = "ID", isAttribute = true)
private Long id;
@JacksonXmlProperty(localName = "TextResourceID", isAttribute = true)
private Integer textResourceID;
@JacksonXmlProperty(localName = "BodyPartId", isAttribute = true)
private Integer bodyPartId;
@JacksonXmlProperty(localName = "MediaResourceID", isAttribute = true)
private Integer mediaResourceID;
@JacksonXmlProperty(localName = "IsUsed", isAttribute = true)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isUsed;
@JacksonXmlProperty(localName = "IsColorable", isAttribute = true)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isColorable;
@JacksonXmlProperty(localName = "Color", isAttribute = true)
private Integer color;
@JacksonXmlProperty(localName = "IsLimited", isAttribute = true)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isLimited;
@JacksonXmlProperty(localName = "Date", isAttribute = true)
private LocalDateTime date;
@JacksonXmlProperty(localName = "Pollution", isAttribute = true)
private Integer pollution;
@JacksonXmlProperty(localName = "IsBodyPart", isAttribute = true)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isBodyPart;
@JacksonXmlProperty(localName = "GoodID", isAttribute = true)
public Long getGoodId() {
return this.id;
}
}

View File

@ -1,12 +1,59 @@
package com.alterdekim.game.component.game;
import com.alterdekim.game.entity.Good;
import com.alterdekim.game.service.GoodsService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@Slf4j
@RequiredArgsConstructor
@Getter
public enum AvatarInventoryType {
Clothes,
Magic,
Smile,
House,
HouseFurniture,
Club,
ClubFurniture,
BodyParts
Clothes_(1),
Caps(4),
Glasses(14),
Boots(32),
Bangles(36),
Suits(40),
Magic(64),
Backgrounds(41),
Phones(-4),
Smile(-5),
House(34),
HouseFurniture(20),
HouseFurnitureWall(22),
Club(58),
ClubFacade(63),
ClubShow(78),
ClubFurniture(59),
ClubInstruments(105),
ClubDigitalStuff(68),
ClubFloor(61),
ClubWallpaper(62),
ClubGames(107),
ClubFood(67),
ClubBeverages(66),
ClubDeserts(65),
Achievements(-1),
BodyParts(-2),
Unknown(-3);
private final Integer goodType;
public static AvatarInventoryType fromGoodType(int goodType) {
for( AvatarInventoryType t : values() ) {
if( goodType == t.goodType ) return t;
}
return Unknown;
}
public static AvatarInventoryType fromGoodId(GoodsService goodsService, long goodId) {
Integer goodType = goodsService.findById(goodId).map(Good::getGoodTypeId).orElse(-3);
return fromGoodType(goodType);
}
}

View File

@ -1,23 +0,0 @@
package com.alterdekim.game.component.game;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum BodyPartType {
Body(3, 202, true, 20),
Legs(2, 201, true, 10),
Ears(8, 206, false, 50),
Eyes(7, 205, false, 30),
Nose(6, 204, false, 40),
Mouth(5, 203, false, 26),
Beak(11, 208, false, 41),
Horn(12, 209, false, 55),
Caps(4, 207, false, 45);
private final int value;
private final long mediaResourceId;
private final boolean isShape;
private final int layerId;
}

View File

@ -6,6 +6,6 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public class ChatMessage {
private Long playerId;
private Integer playerId;
private String text;
}

View File

@ -8,12 +8,23 @@ import lombok.Getter;
public enum CommandType {
UserCommand("$"),
SetLocation("_LS"),
LocationChanges("_LC"),
RemoveUserFromLocation("_UL"),
AddUserToLocation("_UE"),
SetUserAvatarState("_S"),
SetUserAvatarPosition("_P"),
ChatMessage("_C"),
Shoot("_NUS"),
UseMagicAbility("_NUM"),
OnFriendsAdded("_UFLA"),
OnFriendshipRequestAdded("_UFLR"),
OnFriendsRemoved("_UFLD"),
AddNewPhoneMessage("_MP"),
CardMessage("_MC"),
UpdateTickets("_NNT"),
UpdateRoomTeam("_GU"),
LaunchRoomSession("_GL"),
MiniGameAction("_G"),
Unknown("");
private final String value;

View File

@ -1,19 +0,0 @@
package com.alterdekim.game.component.game;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum GoodClothType {
Clothes(1, 212, 36),
Caps(4, 211, 45),
Glasses(14, 210, 31),
Boots(32, 213, 11),
Bangles(36, 214, 56),
Suits(40, 429, 27);
private final int val;
private final long tabMediaResourceId;
private final int layerId;
}

View File

@ -1,7 +0,0 @@
package com.alterdekim.game.component.game;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class LocationObjectInstance {
}

View File

@ -13,6 +13,6 @@ public class Player {
private final String username;
private double x;
private double y;
private int locationId;
private long locationId;
private double state;
}

View File

@ -1,12 +1,11 @@
package com.alterdekim.game.component.game;
import com.alterdekim.game.component.game.avatar.UserAvatar;
import com.alterdekim.game.message.amf.AMFKey;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import java.util.Map;
@ToString
@Getter
@AllArgsConstructor

View File

@ -8,6 +8,7 @@ import lombok.Getter;
public enum RoleFlags {
NONE(0),
MEMBER(2),
BOSS(4),
SA(8),
MODERATOR(131072),
ADMINISTRATOR(262144),

View File

@ -6,7 +6,7 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public class SetPlayerPosition {
private Long userId;
private Integer userId;
private Point point;
private Long tweenerId;
}

View File

@ -6,6 +6,6 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public class SetPlayerState {
private Long playerId;
private Integer playerId;
private Double state;
}

View File

@ -6,7 +6,7 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public class Shoot {
private Long playerId;
private Integer playerId;
private Double x;
private Double y;
}

View File

@ -0,0 +1,9 @@
package com.alterdekim.game.component.game;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class UpdateTickets {
private Integer usualTickets;
private Integer magicTickets;
}

View File

@ -3,7 +3,7 @@ package com.alterdekim.game.component.game;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class AddUserToLocation {
private Long playerId;
private PlayerAvatar avatar;
public class UseMagicAbility {
private Integer userId;
private Integer magicId;
}

View File

@ -13,9 +13,39 @@ public enum UserCommandType {
GetFriendPanelData("_SNFP"),
UpdateUserData("_D"),
GetUserLocation("_LG"),
GetUserLocationById("_LGI"),
GetCatalogInfo("_GCI"),
ChatMessage("_C"),
Shoot("_NUS"),
GetUserInfo("_UI"),
GetUserAvatar("_AG"),
SaveUserAvatarChanges("_AS"),
GetUserUnlocks("_UUG"),
GetOnlineUserFriends("_UFO"),
RevokeUserFriendship("_UFD"),
ApplyUserFriendship("_UFA"),
GetSnInvitePanelData("_SNI"),
GetGrantBlocks("_UGGB"),
UseMagicAbility("_NUM"),
SetDefaultUserPhone("_SDP"),
SetUserBackground("_SDB"),
QueryUserFriendship("_UFQ"),
GetPhoneBalance("_DP"),
PhoneMessage("_MP"),
MarkPhoneMessageAsRead("_MPR"),
DeletePhoneMessage("_MPD"),
CardMessage("_MC"),
MarkCardMessageAsRead("_MCR"),
DeleteCardMessage("_MCD"),
LockHouse("_LL"),
BuyBatch("_BGB"),
GetGame("_GG"),
GameScore("_GS"),
SendGameClose("_GC"),
GameStatistics("_GT"),
RegisterGameWaiting("_GR"),
GetUserHomeLocationData("_LDH"),
SaveLocationChanges("_LC"),
Unknown("");
private final String value;

View File

@ -1,6 +1,8 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.avatar;
import com.alterdekim.game.message.amf.AMFKey;
import com.alterdekim.game.xml.BodyPartTypeSerializer;
import com.alterdekim.game.xml.LayerIdSerializer;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@ -35,4 +37,18 @@ public class BodyAvatarItem {
@AMFKey(name = "GoodTypeID")
private Integer goodTypeId;
public static BodyAvatarItem fromInterface(IBodyAvatarItem i) {
return new BodyAvatarItem(
BodyPartTypeSerializer.parse(i.getBodyPartTypeId()),
i.getId(),
i.getColor(),
i.getIsBodyPart() == 1,
i.getBodyPartId(),
i.getGoodId(),
i.getMediaResourceId(),
LayerIdSerializer.parse(i.getLayerId()),
i.getGoodTypeId()
);
}
}

View File

@ -0,0 +1,24 @@
package com.alterdekim.game.component.game.avatar;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum BodyPartType {
Body(3, 202, true, 20, 48),
Legs(2, 201, true, 10, 47),
Ears(8, 206, false, 50, 70),
Eyes(7, 205, false, 30, 58),
Nose(6, 204, false, 40, 57),
Mouth(5, 203, false, 26, 56),
Beak(11, 208, false, 41, 110),
Horn(12, 209, false, 55, 166),
Caps(4, 207, false, 45, 21);
private final int value;
private final long mediaResourceId;
private final boolean isShape;
private final int layerId;
private final long textResourceId;
}

View File

@ -0,0 +1,21 @@
package com.alterdekim.game.component.game.avatar;
import com.alterdekim.game.component.game.AvatarInventoryType;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum GoodClothType {
Clothes(AvatarInventoryType.Clothes_, 212, 36, 120),
Caps(AvatarInventoryType.Caps, 211, 45, 21),
Glasses(AvatarInventoryType.Glasses, 210, 31, 62),
Boots(AvatarInventoryType.Boots, 213, 11, 123),
Bangles(AvatarInventoryType.Bangles, 214, 56, 24),
Suits(AvatarInventoryType.Suits, 429, 27, 697);
private final AvatarInventoryType val;
private final long tabMediaResourceId;
private final int layerId;
private final int textResourceId;
}

View File

@ -0,0 +1,37 @@
package com.alterdekim.game.component.game.avatar;
import com.alterdekim.game.xml.BodyPartTypeSerializer;
import com.alterdekim.game.xml.LayerIdSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public interface IBodyAvatarItem {
@JacksonXmlProperty(localName = "BodyPartTypeId", isAttribute = true)
@JsonSerialize(using = BodyPartTypeSerializer.class)
Object getBodyPartTypeId();
@JacksonXmlProperty(localName = "Id", isAttribute = true)
Long getId();
@JacksonXmlProperty(localName = "Color", isAttribute = true)
Integer getColor();
@JacksonXmlProperty(localName = "IsBodyPart", isAttribute = true)
Integer getIsBodyPart();
@JacksonXmlProperty(localName = "BodyPartId", isAttribute = true)
Integer getBodyPartId();
@JacksonXmlProperty(localName = "GoodID", isAttribute = true)
Long getGoodId();
@JacksonXmlProperty(localName = "MediaResourceID", isAttribute = true)
Integer getMediaResourceId();
@JacksonXmlProperty(localName = "LayerID", isAttribute = true)
@JsonSerialize(using = LayerIdSerializer.class)
Object getLayerId();
@JacksonXmlProperty(localName = "GoodTypeID", isAttribute = true)
Integer getGoodTypeId();
}

View File

@ -1,4 +1,4 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.avatar;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@ -6,14 +6,14 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class InitMagicAbility {
public interface InitMagicAbility {
@JacksonXmlProperty(localName = "Id", isAttribute = true)
private Integer id;
Integer getId();
@JacksonXmlProperty(localName = "ExpirationDate", isAttribute = true)
private String expirationDate;
String getExpirationDate();
@JacksonXmlProperty(localName = "IsLimited", isAttribute = true)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isLimited;
Integer getIsLimited();
}

View File

@ -1,5 +1,6 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.avatar;
import com.alterdekim.game.component.game.avatar.BodyAvatarItem;
import com.alterdekim.game.message.amf.AMFKey;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@ -0,0 +1,10 @@
package com.alterdekim.game.component.game.friends;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class OneFR {
private UserFriend userFriend;
}

View File

@ -0,0 +1,21 @@
package com.alterdekim.game.component.game.friends;
import com.alterdekim.game.message.amf.AMFKey;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class UserFriend {
@AMFKey(name = "UserId")
private Integer userId;
@AMFKey(name = "SnName")
private String snName;
@AMFKey(name = "UserName")
private String userName;
@AMFKey(name = "IsOnline")
private Boolean isOnline;
}

View File

@ -0,0 +1,39 @@
package com.alterdekim.game.component.game.home;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@AllArgsConstructor
public class HomeInventoryGroup {
@JacksonXmlProperty(isAttribute = true, localName = "ID")
@Getter
private String id;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectTypeId")
private Integer objectTypeId;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectId")
@Getter
@Setter
private Long objectId;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectRefTypeId")
private Integer objectRefTypeId;
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
private Integer mediaResourceID;
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
private Integer textResourceID;
@JacksonXmlProperty(isAttribute = false, localName = "object")
@JacksonXmlElementWrapper(useWrapping = false, localName = "object")
@Getter
private List<HomeInventoryObject> object;
}

View File

@ -0,0 +1,16 @@
package com.alterdekim.game.component.game.home;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class HomeInventoryObject {
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private Integer id;
@JacksonXmlProperty(isAttribute = true, localName = "IsActive")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isActive;
}

View File

@ -0,0 +1,88 @@
package com.alterdekim.game.component.game.home;
import com.alterdekim.game.component.game.ClubAccessType;
import com.alterdekim.game.xml.ClubAccessTypeSerializer;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class HomeLocation {
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private Integer id;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectTypeId")
private Integer objectTypeId;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectId")
private Long objectId;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectRefTypeId")
private Integer objectRefTypeId;
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
private Integer mediaResourceID;
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
private Integer textResourceID;
@JacksonXmlProperty(isAttribute = true, localName = "IsHome")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isHome;
@JacksonXmlProperty(isAttribute = true, localName = "IsClub")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isClub;
@JacksonXmlProperty(isAttribute = true, localName = "IsVisaAccessPermitted")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean IsVisaAccessPermitted;
@JacksonXmlProperty(isAttribute = true, localName = "IsCurrent")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isCurrent;
@JacksonXmlProperty(isAttribute = true, localName = "IsLocked")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isLocked;
@JacksonXmlProperty(isAttribute = true, localName = "ClubAccessType")
@JsonSerialize(using = ClubAccessTypeSerializer.class)
private ClubAccessType clubAccessType;
@JacksonXmlProperty(isAttribute = true, localName = "ClubCost")
private Integer clubCost;
@JacksonXmlProperty(isAttribute = true, localName = "ClubRate")
private Integer clubRate;
@JacksonXmlProperty(isAttribute = true)
private Double x;
@JacksonXmlProperty(isAttribute = true)
private Double y;
@JacksonXmlProperty(isAttribute = true, localName = "Frame")
private Integer frame;
@JacksonXmlProperty(isAttribute = true, localName = "TweenerId")
private Integer tweenerId;
@JacksonXmlProperty(isAttribute = true, localName = "IsVisible")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isVisible;
@JacksonXmlProperty(isAttribute = true, localName = "IsEnabled")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isEnabled;
@JacksonXmlProperty(isAttribute = true, localName = "IsPositionHeld")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isPositionHeld;
@JacksonXmlProperty(isAttribute = true, localName = "IsDraggable")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isDraggable;
}

View File

@ -0,0 +1,21 @@
package com.alterdekim.game.component.game.home;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import java.util.List;
@AllArgsConstructor
@JacksonXmlRootElement(localName = "root")
public class HomeStuff {
@JacksonXmlProperty(isAttribute = false, localName = "inventory")
@JacksonXmlElementWrapper(useWrapping = true, localName = "inventory")
private List<HomeInventoryGroup> inventory;
@JacksonXmlProperty(isAttribute = false, localName = "locations")
@JacksonXmlElementWrapper(useWrapping = true, localName = "locations")
private List<HomeLocation> locations;
}

View File

@ -0,0 +1,12 @@
package com.alterdekim.game.component.game.inventory;
import com.alterdekim.game.message.amf.AMFKey;
import lombok.AllArgsConstructor;
import java.util.List;
@AllArgsConstructor
public class BuyGoodResult {
@AMFKey(name = "GoodInfo")
private List<Integer> goodInfo;
}

View File

@ -0,0 +1,20 @@
package com.alterdekim.game.component.game.inventory;
import com.alterdekim.game.message.amf.AMFKey;
import lombok.AllArgsConstructor;
import java.util.List;
@AllArgsConstructor
public class BuyGoodResultGood {
private BuyGoodBody body;
@AllArgsConstructor
public static class BuyGoodBody {
@AMFKey(name = "Error")
private Boolean error;
@AMFKey(name = "GoodInfo")
private List<Integer> goodInfo;
}
}

View File

@ -0,0 +1,43 @@
package com.alterdekim.game.component.game.inventory;
import com.alterdekim.game.entity.Incompatible;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JacksonXmlRootElement(localName = "user_avatar")
@JsonPropertyOrder({"Shape", "BodyParts", "Inventory", "Backgrounds", "Phones", "SportInventory", "Incompatibles"})
public class Inventory {
@JacksonXmlProperty(localName = "Shape")
private InventoryTab shape;
@JacksonXmlProperty(localName = "BodyParts")
private InventoryTab bodyparts;
@JacksonXmlProperty(localName = "Inventory")
private InventoryTab inventory;
@JacksonXmlProperty(localName = "Backgrounds")
private InventoryList backgrounds;
@JacksonXmlProperty(localName = "Phones")
private InventoryList phones;
@JacksonXmlProperty(localName = "SportInventory")
private InventoryList sportinv;
@JacksonXmlProperty(localName = "Incompatibles")
@JacksonXmlElementWrapper(useWrapping = true, localName = "Incompatibles")
private List<Incompatible> items;
}

View File

@ -0,0 +1,36 @@
package com.alterdekim.game.component.game.inventory;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class InventoryGroup {
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private int id;
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
private long textResourceId;
@JacksonXmlProperty(isAttribute = true, localName = "IsUsed")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isUsed;
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
private long mediaResourceId;
@JacksonXmlProperty(isAttribute = true, localName = "LayerID")
private int layerId;
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = false, localName = "items")
private List<InventoryItem> items;
}

View File

@ -0,0 +1,42 @@
package com.alterdekim.game.component.game.inventory;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public interface InventoryItem {
@JacksonXmlProperty(isAttribute = true, localName = "ID")
Long getId();
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
Long getTextResourceId();
@JacksonXmlProperty(isAttribute = true, localName = "BodyPartId")
Long getBodyPartId();
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
Integer getMediaResourceId();
@JacksonXmlProperty(isAttribute = true, localName = "IsUsed")
Integer getIsUsed();
@JacksonXmlProperty(isAttribute = true, localName = "IsColorable")
Integer getIsColorable();
@JacksonXmlProperty(isAttribute = true, localName = "Color")
Integer getColor();
@JacksonXmlProperty(isAttribute = true, localName = "IsLimited")
Integer getIsLimited();
@JacksonXmlProperty(isAttribute = true, localName = "Date")
String getDate();
@JacksonXmlProperty(isAttribute = true, localName = "Pollution")
Integer getPollution();
@JacksonXmlProperty(isAttribute = true, localName = "IsBodyPart")
Integer getIsBodyPart();
@JacksonXmlProperty(isAttribute = true, localName = "PhoneId")
Long getPhoneId();
}

View File

@ -0,0 +1,22 @@
package com.alterdekim.game.component.game.inventory;
import com.alterdekim.game.entity.Good;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class InventoryList {
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
private Integer textResourceId;
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = false, localName = "items")
private List<InventoryItem> items;
}

View File

@ -0,0 +1,22 @@
package com.alterdekim.game.component.game.inventory;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class InventoryTab {
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
private int textResourceId;
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = false, localName = "group")
private List<InventoryGroup> items;
}

View File

@ -0,0 +1,10 @@
package com.alterdekim.game.component.game.minigame;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class MiniGameAction {
private String actionName;
private Integer number;
private String id;
}

View File

@ -0,0 +1,12 @@
package com.alterdekim.game.component.game.minigame;
import lombok.AllArgsConstructor;
import java.util.List;
import java.util.Map;
@AllArgsConstructor
public class MultiplayerMinigameLaunch {
private Map<String, List<MultiplayerMinigameWaiting.Players>> players;
private String sessionDescriptor;
}

View File

@ -0,0 +1,23 @@
package com.alterdekim.game.component.game.minigame;
import com.alterdekim.game.message.amf.AMFKey;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
@AllArgsConstructor
public class MultiplayerMinigameWaiting {
private Map<String, List<Players>> players;
private Integer number;
private Boolean flag;
@AllArgsConstructor
public static class Players {
@AMFKey(name = "ID")
private Integer id;
@AMFKey(name = "Name")
private String name;
}
}

View File

@ -0,0 +1,22 @@
package com.alterdekim.game.component.game.response.init;
import com.alterdekim.game.component.game.avatar.IBodyAvatarItem;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
@Getter
@AllArgsConstructor
@JacksonXmlRootElement(localName = "user_info")
public class GetUserInfo {
@JacksonXmlProperty(localName = "user")
private UserInfo user;
@JacksonXmlProperty(localName = "avatar")
@JacksonXmlElementWrapper(useWrapping = true, localName = "avatar")
private List<IBodyAvatarItem> avatar;
}

View File

@ -1,4 +1,4 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.response.init;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;

View File

@ -1,29 +1,42 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.response.init;
import com.alterdekim.game.component.game.ClubAccessType;
import com.alterdekim.game.component.game.RoleFlags;
import com.alterdekim.game.component.game.avatar.InitMagicAbility;
import com.alterdekim.game.xml.ClubAccessTypeSerializer;
import com.alterdekim.game.xml.LocalDateTimeSerializer;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.alterdekim.game.xml.RoleFlagsSerializer;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.List;
@AllArgsConstructor
@Getter
@Setter
@JacksonXmlRootElement(localName = "user")
public class UserInfo {
@JacksonXmlProperty(isAttribute = true, localName = "UserId")
private Long userId;
private Integer userId;
@JacksonXmlProperty(isAttribute = true, localName = "Id")
private Integer id;
@JacksonXmlProperty(isAttribute = true, localName = "RoleFlags")
@JsonSerialize(using = RoleFlagsSerializer.class)
private RoleFlags roleFlags;
@JacksonXmlProperty(isAttribute = true, localName = "IsVoteForInstructorAllowed")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isVoteForInstructorAllowed;
@JacksonXmlProperty(isAttribute = true, localName = "IsLimited")
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isLimited;
@ -52,6 +65,9 @@ public class UserInfo {
@JsonSerialize(using = ClubAccessTypeSerializer.class)
private ClubAccessType clubAccessType;
@JacksonXmlProperty(isAttribute = true, localName = "ClubCost")
private Integer clubCost;
@JacksonXmlProperty(isAttribute = true, localName = "IsFriend")
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isFriend;
@ -72,7 +88,7 @@ public class UserInfo {
private Integer phoneId;
@JacksonXmlProperty(isAttribute = true, localName = "BackgroundId")
private Integer backgroundId;
private Long backgroundId;
@JacksonXmlProperty(isAttribute = true, localName = "CampId")
private Integer campId;
@ -117,4 +133,13 @@ public class UserInfo {
@JacksonXmlProperty(isAttribute = true, localName = "Name")
private String name;
// LocationTypeID
@JacksonXmlProperty(isAttribute = true, localName = "AchievementsList")
private String achievementsList;
@JacksonXmlProperty(isAttribute = true, localName = "user_magic_abilities")
@JacksonXmlElementWrapper(useWrapping = true, localName = "user_magic_abilities")
private List<InitMagicAbility> userMagicAbilities;
}

View File

@ -1,6 +1,7 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.response.init;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.alterdekim.game.component.game.avatar.InitMagicAbility;
import com.alterdekim.game.entity.Smile;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@ -22,11 +23,11 @@ public class UserInitInfo {
@JacksonXmlProperty(localName = "user_phone")
private UserPhone userPhone;
@JsonProperty(value = "user_magic_abilities")
@JacksonXmlProperty(localName = "user_magic_abilities")
@JacksonXmlElementWrapper(useWrapping = true, localName = "user_magic_abilities")
private List<InitMagicAbility> magicAbilities;
@JsonProperty(value = "avatar")
@JacksonXmlElementWrapper(useWrapping = true, localName = "avatar")
private List<AvatarInventoryItem> avatar;
@JacksonXmlProperty(localName = "smiles")
@JacksonXmlElementWrapper(useWrapping = true, localName = "smiles")
private List<Smile> smiles;
}

View File

@ -1,4 +1,4 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.response.init;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;

View File

@ -0,0 +1,10 @@
package com.alterdekim.game.component.game.response.location;
import com.alterdekim.game.component.game.PlayerAvatar;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class AddUserToLocation {
private Integer playerId;
private PlayerAvatar avatar;
}

View File

@ -1,5 +1,6 @@
package com.alterdekim.game.component.game;
package com.alterdekim.game.component.game.response.location;
import com.alterdekim.game.entity.LocationObjectInstance;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
@ -47,7 +48,12 @@ public class LocationObject {
@JacksonXmlProperty(isAttribute = true, localName = "Name")
private String name;
//todo: add location objects
@JacksonXmlProperty(isAttribute = true, localName = "OwnerId")
private Integer ownerId;
@JacksonXmlProperty(isAttribute = true, localName = "OwnerName")
private String ownerName;
@JacksonXmlProperty(isAttribute = false, localName = "object")
@JacksonXmlElementWrapper(useWrapping = false, localName = "object")
private List<LocationObjectInstance> objects;

View File

@ -3,41 +3,33 @@ package com.alterdekim.game.component.rtmp;
import com.alterdekim.game.component.GameServer;
import com.alterdekim.game.message.*;
import com.alterdekim.game.message.amf.*;
import com.alterdekim.game.message.serializer.BinaryMessageSerializer;
import com.alterdekim.game.utils.RTMPUtils;
import com.alterdekim.game.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.javatuples.Pair;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.*;
@Slf4j
public class ConnectedProcessor extends ConnectionProcessor {
private final Long startTimestamp;
private ConnectedState state;
private List<Byte> message;
private Integer expectedMessageLength;
private Integer lastStreamId;
private byte[] previousHeader;
private GameServer gameServer;
private Long playerId;
private final List<Byte> message;
private byte lastStreamId;
private final GameServer gameServer;
private Integer playerId;
private final RTMPSession rtmpSessionInfo;
public ConnectedProcessor(InputStream inputStream, OutputStream outputStream, Socket sock, GameServer gameServer) {
super(inputStream, outputStream, sock);
this.state = ConnectedState.WAIT_FOR_MESSAGE;
this.message = new ArrayList<>();
this.gameServer = gameServer;
this.previousHeader = new byte[11];
this.startTimestamp = System.currentTimeMillis();
this.rtmpSessionInfo = new RTMPSession();
}
@Override
@ -47,43 +39,87 @@ public class ConnectedProcessor extends ConnectionProcessor {
@Override
public ConnectionState process() throws IOException {
int b = this.getInputStream().read();
byte[] b1 = new byte[1]; // this was left as is due to underlying conversion between int and byte types.
int b = this.getInputStream().read(b1);
if (b == -1) {
close(); return ConnectionState.CONNECTED;
}
if( this.state == ConnectedState.WAIT_FOR_MESSAGE && b != 0x03 && b != 0x43 && b != 0x83 && b != 0x02 && b != 0xC3 ) {
log.info("process() WAIT_FOR_MESSAGE not 03,43,83");
return ConnectionState.CONNECTED;
}
this.state = switch(state) {
case WAIT_FOR_MESSAGE -> processWaitForMessage(parseChunkHeader(b));
case LISTENS_FOR_MESSAGE -> processListensForMessage((byte) b);
case WAIT_FOR_MESSAGE -> processWaitForMessage(b1[0]);
case LISTENS_FOR_MESSAGE -> processListensForMessage(b1[0]);
};
return ConnectionState.CONNECTED;
}
private ConnectedState processWaitForMessage(Pair<ChunkHeaderType, Integer> packetHeader) {
private ConnectedState processWaitForMessage(byte b) {
try {
byte[] header = switch (packetHeader.getValue0()) {
case Full -> new byte[11];
case WithoutStreamId -> new byte[7];
case OnlyTimestamp -> new byte[3];
default -> new byte[0];
};
if(this.getInputStream().read(header) == -1) return ConnectedState.WAIT_FOR_MESSAGE;
if(header.length == 11) this.lastStreamId = BinaryMessageSerializer.deserializeInteger(Arrays.copyOfRange(header, 7, 11));
this.message.clear();
this.expectedMessageLength = BinaryMessageSerializer.deserializeInteger(
Arrays.copyOfRange( header.length >= 7 ? header : this.previousHeader, 3, 6)
);
if( header.length >= 7 ) this.previousHeader = header;
if( header.length == 11 && packetHeader.getValue1() == 2 ) {
byte[] b = new byte[4];
if( this.getInputStream().read(b) == -1 ) return ConnectedState.WAIT_FOR_MESSAGE;
this.getOutputStream().write(new byte[] {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, b[0], b[1], b[2], b[3]});
this.getOutputStream().flush();
RTMPHeader header = new RTMPHeader();
header.setChunkType(RTMPHeader.ChunkType.fromByte((byte) ((0xC0 & b) >> 6)));
header.setChunkStreamId((byte) (b & 0x3F));
if( header.getChunkStreamId() != ChunkStreamInfo.CONTROL_CHANNEL &&
header.getChunkStreamId() != ChunkStreamInfo.RTMP_COMMAND_CHANNEL &&
header.getChunkStreamId() != ChunkStreamInfo.RTMP_STREAM_CHANNEL ) {
return ConnectedState.WAIT_FOR_MESSAGE;
}
switch (header.getChunkType()) {
case TYPE_0_FULL -> { // b00 = 12 byte header (full header)
// Read bytes 1-3: Absolute timestamp
header.setAbsoluteTimestamp(RTMPUtils.readUnsignedInt24(this.getInputStream()));
header.setTimestampDelta(0);
// Read bytes 4-6: Packet length
header.setPacketLength(RTMPUtils.readUnsignedInt24(this.getInputStream()));
// Read byte 7: Message type ID
byte[] b1 = new byte[1];
this.getInputStream().read(b1);
header.setMessageType(RTMPHeader.MessageType.valueOf(b1[0]));
// Read bytes 8-11: Message stream ID (apparently little-endian order)
byte[] messageStreamIdBytes = new byte[4];
this.getInputStream().read(messageStreamIdBytes);
header.setMessageStreamId(RTMPUtils.toUnsignedInt32LittleEndian(messageStreamIdBytes));
}
case TYPE_1_RELATIVE_LARGE -> { // b01 = 8 bytes - like type 0. not including message stream ID (4 last bytes)
// Read bytes 1-3: Timestamp delta
header.setTimestampDelta(RTMPUtils.readUnsignedInt24(this.getInputStream()));
// Read bytes 4-6: Packet length
header.setPacketLength(RTMPUtils.readUnsignedInt24(this.getInputStream()));
// Read byte 7: Message type ID
byte[] b1 = new byte[1];
this.getInputStream().read(b1);
header.setMessageType(RTMPHeader.MessageType.valueOf(b1[0]));
RTMPHeader prevHeader = rtmpSessionInfo.getLastHeader(header.getChunkStreamId());
try {
header.setMessageStreamId(prevHeader.getMessageStreamId());
header.setAbsoluteTimestamp(prevHeader.getAbsoluteTimestamp() + header.getTimestampDelta());
} catch (NullPointerException ex) {
header.setMessageStreamId(0);
header.setAbsoluteTimestamp(header.getTimestampDelta());
}
}
case TYPE_2_RELATIVE_TIMESTAMP_ONLY -> { // b10 = 4 bytes - Basic Header and timestamp (3 bytes) are included
// Read bytes 1-3: Timestamp delta
header.setTimestampDelta(RTMPUtils.readUnsignedInt24(this.getInputStream()));
RTMPHeader prevHeader = rtmpSessionInfo.getLastHeader(header.getChunkStreamId());
header.setPacketLength(prevHeader.getPacketLength());
header.setMessageType(prevHeader.getMessageType());
header.setMessageStreamId(prevHeader.getMessageStreamId());
header.setAbsoluteTimestamp(prevHeader.getAbsoluteTimestamp() + header.getTimestampDelta());
}
case TYPE_3_RELATIVE_SINGLE_BYTE -> { // b11 = 1 byte: basic header only
RTMPHeader prevHeader = rtmpSessionInfo.getLastHeader(header.getChunkStreamId());
header.setTimestampDelta(prevHeader.getTimestampDelta());
header.setAbsoluteTimestamp(prevHeader.getAbsoluteTimestamp() + header.getTimestampDelta());
header.setPacketLength(prevHeader.getPacketLength());
header.setMessageType(prevHeader.getMessageType());
header.setMessageStreamId(prevHeader.getMessageStreamId());
}
}
this.message.clear();
this.lastStreamId = header.getChunkStreamId();
this.rtmpSessionInfo.chunkStreams.put(this.lastStreamId, header);
return ConnectedState.LISTENS_FOR_MESSAGE;
} catch (IOException e) {
log.error("ConnectedProcessor.processWaitForMessage()", e);
@ -92,13 +128,13 @@ public class ConnectedProcessor extends ConnectionProcessor {
}
private ConnectedState processListensForMessage(byte b) {
if(this.message.size() >= this.expectedMessageLength) {
if(this.message.size() >= this.rtmpSessionInfo.getLastHeader(this.lastStreamId).getPacketLength()) {
this.processMessage();
return ConnectedState.WAIT_FOR_MESSAGE;
}
if( b == (byte) 0xC3 ) { this.expectedMessageLength--; return ConnectedState.LISTENS_FOR_MESSAGE; }
if( b == (byte) 0xC3 ) { this.rtmpSessionInfo.getLastHeader(this.lastStreamId).setPacketLength(this.rtmpSessionInfo.getLastHeader(this.lastStreamId).getPacketLength()-1); return ConnectedState.LISTENS_FOR_MESSAGE; }
this.message.add(b);
if(this.message.size() >= this.expectedMessageLength) {
if(this.message.size() >= this.rtmpSessionInfo.getLastHeader(this.lastStreamId).getPacketLength()) {
this.processMessage();
return ConnectedState.WAIT_FOR_MESSAGE;
}
@ -106,15 +142,34 @@ public class ConnectedProcessor extends ConnectionProcessor {
}
private void processMessage() {
switch (this.lastStreamId) {
case ChunkStreamInfo.CONTROL_CHANNEL -> processControlChannel();
case ChunkStreamInfo.RTMP_COMMAND_CHANNEL -> processCommandChannel();
case ChunkStreamInfo.RTMP_STREAM_CHANNEL -> processStreamChannel();
default -> log.warn("Unknown channel id: {}", this.lastStreamId);
}
}
private void processControlChannel() {
byte[] bytes = SerializerUtils.bytesToPrimitive(message);
log.info("ConnectedProcessor.processMessage() controlMessage: {}", StringUtils.bytesToHex(bytes));
}
private void processCommandChannel() {
if( this.rtmpSessionInfo.getLastHeader(this.lastStreamId).getMessageType() != RTMPHeader.MessageType.COMMAND_AMF0 ) {
log.info("ConnectedProcessor.processMessage() type: {}", this.rtmpSessionInfo.getLastHeader(this.lastStreamId).getMessageType());
return;
}
byte[] bytes = SerializerUtils.bytesToPrimitive(message);
log.info("ConnectedProcessor.processMessage() messageString: {}", StringUtils.bytesToHex(bytes));
try {
List<AMFObject> mr = AMFDeserializer.deserialize(message);
List<AMFObject> mr = AMFDeserializer.newInstance(message).deserialize();
if( !mr.isEmpty() &&
mr.get(0).getType() == AMFValueType.STRING &&
mr.get(0).getValue().equals("connect") ) {
this.playerId = Long.parseLong((String) mr.get(3).getValue());
this.gameServer.onConnect(this.playerId, (String) mr.get(5).getValue(), this);
mr.get(0).toString().equals("connect") ) {
this.playerId = mr.get(3).getInt();
this.gameServer.onConnect(this.playerId, mr.get(5).toString(), this);
this.getOutputStream().write( StringUtils.hexStringToByteArray("020000000000040500000000002625A0020000000000050600000000002625A00202000000000004010000000000001000030000000000F214000000000200075F726573756C74003FF0000000000000030006666D7356657202000E464D532F342C302C302C31313231000C6361706162696C697469657300406FE0000000000000046D6F6465003FF00000000000000000090300056C6576656C0200067374617475730004636F646502001D4E6574436F6E6E656374696F6E2E436F6E6E6563742E53756363657373000B6465736372697074696F6E020015436F6E6E656374696F6E207375636365656465642E000E6F626A656374456E636F64696E670000000000000000000004646174610800000000000776657273696F6E02000A342C302C302C31313231000009000009") );
this.getOutputStream().flush();
return;
@ -125,9 +180,8 @@ public class ConnectedProcessor extends ConnectionProcessor {
}
}
// returns chunk type and stream id
private Pair<ChunkHeaderType, Integer> parseChunkHeader(int b) {
return Pair.with(ChunkHeaderType.fromInt((b & 0xC0) >> 6), b & 0x3F);
private void processStreamChannel() {
log.warn("There's stream message.");
}
@Override
@ -148,7 +202,7 @@ public class ConnectedProcessor extends ConnectionProcessor {
cnt++;
}
}
l.addAll(int2bytes((int) ((System.currentTimeMillis() - this.startTimestamp) / 1000L), 3));
l.addAll(int2bytes((int) ((System.currentTimeMillis() - this.rtmpSessionInfo.getLastHeader(this.lastStreamId).getAbsoluteTimestamp()) / 1000L), 3));
l.addAll(int2bytes(data.size() - cnt, 3));
l.add((byte) 0x14);
l.addAll(int2bytes(this.lastStreamId, 4));
@ -170,21 +224,27 @@ public class ConnectedProcessor extends ConnectionProcessor {
super.close();
}
@AllArgsConstructor
private enum ChunkHeaderType {
Full(0),
WithoutStreamId(1),
OnlyTimestamp(2),
UsePrevious(3),
Unknown(4);
private class RTMPSession {
private final int type;
@Getter
@Setter
private int chunkSize = 128;
private static ChunkHeaderType fromInt(int b) {
for( ChunkHeaderType c : values() ) {
if( c.type == b ) return c;
private Map<Byte, RTMPHeader> chunkStreams = new HashMap<>();
public RTMPHeader getLastHeader(byte chunkStreamId) {
RTMPHeader chunkStreamInfo = chunkStreams.get(chunkStreamId);
if (chunkStreamInfo == null) {
chunkStreamInfo = new RTMPHeader();
chunkStreams.put(chunkStreamId, chunkStreamInfo);
}
return Unknown;
return chunkStreamInfo;
}
}
private interface ChunkStreamInfo {
byte RTMP_STREAM_CHANNEL = 0x08;
byte RTMP_COMMAND_CHANNEL = 0x03;
byte CONTROL_CHANNEL = 0x02;
}
}

View File

@ -1,6 +1,7 @@
package com.alterdekim.game.component.rtmp;
import com.alterdekim.game.crypto.HMAC;
import com.alterdekim.game.message.ByteMessage;
import com.alterdekim.game.message.SerializerUtils;
import com.alterdekim.game.message.serializer.BinaryMessageSerializer;
@ -14,6 +15,7 @@ import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
@Slf4j
@ -21,8 +23,26 @@ public class HandshakeProcessor extends ConnectionProcessor {
private HandshakeState handshakeState;
private static final int PROTOCOL_VERSION = 0x03;
private static final int HANDSHAKE_SIZE = 1536;
private static final int DIGEST_OFFSET_INDICATOR_POS = 772;
private static final int SHA256_DIGEST_SIZE = 32;
private static final byte[] GENUINE_FP_KEY = {
(byte) 0x47, (byte) 0x65, (byte) 0x6E, (byte) 0x75, (byte) 0x69, (byte) 0x6E, (byte) 0x65, (byte) 0x20,
(byte) 0x41, (byte) 0x64, (byte) 0x6F, (byte) 0x62, (byte) 0x65, (byte) 0x20, (byte) 0x46, (byte) 0x6C,
(byte) 0x61, (byte) 0x73, (byte) 0x68, (byte) 0x20, (byte) 0x50, (byte) 0x6C, (byte) 0x61, (byte) 0x79,
(byte) 0x65, (byte) 0x72, (byte) 0x20, (byte) 0x30, (byte) 0x30, (byte) 0x31, // Genuine Adobe Flash Player 001
(byte) 0xF0, (byte) 0xEE, (byte) 0xC2, (byte) 0x4A, (byte) 0x80, (byte) 0x68, (byte) 0xBE, (byte) 0xE8,
(byte) 0x2E, (byte) 0x00, (byte) 0xD0, (byte) 0xD1, (byte) 0x02, (byte) 0x9E, (byte) 0x7E, (byte) 0x57,
(byte) 0x6E, (byte) 0xEC, (byte) 0x5D, (byte) 0x2D, (byte) 0x29, (byte) 0x80, (byte) 0x6F, (byte) 0xAB,
(byte) 0x93, (byte) 0xB8, (byte) 0xE6, (byte) 0x36, (byte) 0xCF, (byte) 0xEB, (byte) 0x31, (byte) 0xAE};
private final Random random;
public HandshakeProcessor(InputStream inputStream, OutputStream outputStream, Socket sock) {
super(inputStream, outputStream, sock);
this.random = new Random();
this.handshakeState = HandshakeState.C0S0;
}
@ -34,38 +54,71 @@ public class HandshakeProcessor extends ConnectionProcessor {
@Override
public ConnectionState process() throws IOException {
switch (handshakeState) {
case C0S0:
processFirstMessage();
break;
case C1S1:
processSecondMessage();
break;
case C2S2:
case C0S0 -> processC0();
case C1S1 -> processC1();
case C2S2 -> {
return processThirdMessage();
}
}
return getState();
}
private void processFirstMessage() throws IOException {
byte[] b = new byte[1];
if( this.getInputStream().read(b) == -1 || b[0] != 0x03 ) {close(); return;}
private void processC0() throws IOException {
int b = this.getInputStream().read();
if( b != PROTOCOL_VERSION ) {close(); return;}
this.getOutputStream().write(b);
this.handshakeState = HandshakeState.C1S1;
}
private void processSecondMessage() throws IOException {
byte[] b = new byte[1536];
private void processC1() throws IOException {
byte[] b = new byte[HANDSHAKE_SIZE];
if( this.getInputStream().read(b) == -1 ) { close(); return; }
this.getOutputStream().write(b);
this.handshakeState = HandshakeState.C2S2;
}
private ConnectionState processThirdMessage() throws IOException {
byte[] b = new byte[1536];
byte[] b = new byte[HANDSHAKE_SIZE];
if( this.getInputStream().read(b) == -1 ) { close(); return ConnectionState.HANDSHAKE; }
List<Byte> response = new ArrayList<>();
IntStream.range(0, 1536).forEach(i -> response.add( (byte) ((Math.random() * 253) + 1) ) );
write(response);
final int digestOffset = random.nextInt(HANDSHAKE_SIZE - DIGEST_OFFSET_INDICATOR_POS - 4 - 8 - SHA256_DIGEST_SIZE);
final int absoluteDigestOffset = ((digestOffset % 728) + DIGEST_OFFSET_INDICATOR_POS + 4);
int remaining = digestOffset;
final byte[] digestOffsetBytes = new byte[4];
for (int i = 3; i >= 0; i--) {
if (remaining > 255) {
digestOffsetBytes[i] = (byte)255;
remaining -= 255;
} else {
digestOffsetBytes[i] = (byte)remaining;
remaining -= remaining;
}
}
byte[] partBeforeDigest = new byte[absoluteDigestOffset];
random.nextBytes(partBeforeDigest);
byte[] timeStamp = SerializerUtils.bytesToPrimitive(BinaryMessageSerializer.serializeInteger((int) (System.currentTimeMillis() / 1000)));
System.arraycopy(timeStamp, 0, partBeforeDigest, 0, 4);
System.arraycopy(new byte[]{(byte) 0x80, 0x00, 0x07, 0x02}, 0, partBeforeDigest, 4, 4);
byte[] partAfterDigest = new byte[HANDSHAKE_SIZE - absoluteDigestOffset - SHA256_DIGEST_SIZE];
random.nextBytes(partAfterDigest);
System.arraycopy(digestOffsetBytes, 0, partBeforeDigest, DIGEST_OFFSET_INDICATOR_POS, 4);
byte[] tempBuffer = new byte[HANDSHAKE_SIZE - SHA256_DIGEST_SIZE];
System.arraycopy(partBeforeDigest, 0, tempBuffer, 0, partBeforeDigest.length);
System.arraycopy(partAfterDigest, 0, tempBuffer, partBeforeDigest.length, partAfterDigest.length);
HMAC crypto = new HMAC();
byte[] digest = crypto.calculateHmacSHA256(tempBuffer, GENUINE_FP_KEY, 30);
this.getOutputStream().write(partBeforeDigest);
this.getOutputStream().write(digest);
this.getOutputStream().write(partAfterDigest);
this.getOutputStream().flush();
return ConnectionState.CONNECTED;
}

View File

@ -0,0 +1,182 @@
package com.alterdekim.game.component.rtmp;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
@ToString
@Getter
@Setter
@NoArgsConstructor
public class RTMPHeader {
private ChunkType chunkType;
private byte chunkStreamId;
private int absoluteTimestamp;
private int timestampDelta = -1;
private int packetLength;
private MessageType messageType;
private int messageStreamId;
@Getter
@RequiredArgsConstructor
public enum ChunkType {
/**
* Full 12-byte RTMP chunk header
*/
TYPE_0_FULL((byte) 0x00, 12),
/**
* Relative 8-byte RTMP chunk header (message stream ID is not included)
*/
TYPE_1_RELATIVE_LARGE((byte) 0x01, 8),
/**
* Relative 4-byte RTMP chunk header (only timestamp delta)
*/
TYPE_2_RELATIVE_TIMESTAMP_ONLY((byte) 0x02, 4),
/**
* Relative 1-byte RTMP chunk header (no "real" header, just the 1-byte indicating chunk header type & chunk stream ID)
*/
TYPE_3_RELATIVE_SINGLE_BYTE((byte) 0x03, 1);
/**
* The byte value of this chunk header type
*/
private final byte value;
/**
* The full size (in bytes) of this RTMP header (including the basic header byte)
*/
private final int size;
public static ChunkType fromByte(byte b) {
for( ChunkType c : values() ) {
if( c.value == b ) return c;
}
return TYPE_3_RELATIVE_SINGLE_BYTE;
}
}
@Slf4j
@Getter
@RequiredArgsConstructor
public enum MessageType {
/**
* Protocol control message 1
* Set Chunk Size, is used to notify the peer a new maximum chunk size to use.
*/
SET_CHUNK_SIZE((byte) 0x01),
/**
* Protocol control message 2
* Abort Message, is used to notify the peer if it is waiting for chunks
* to complete a message, then to discard the partially received message
* over a chunk stream and abort processing of that message.
*/
ABORT((byte) 0x02),
/**
* Protocol control message 3
* The client or the server sends the acknowledgment to the peer after
* receiving bytes equal to the window size. The window size is the
* maximum number of bytes that the sender sends without receiving
* acknowledgment from the receiver.
*/
ACKNOWLEDGEMENT((byte) 0x03),
/**
* Protocol control message 4
* The client or the server sends this message to notify the peer about
* the user control events. This message carries Event type and Event
* data.
* Also known as a PING message in some RTMP implementations.
*/
USER_CONTROL_MESSAGE((byte) 0x04),
/**
* Protocol control message 5
* The client or the server sends this message to inform the peer which
* window size to use when sending acknowledgment.
* Also known as ServerBW ("server bandwidth") in some RTMP implementations.
*/
WINDOW_ACKNOWLEDGEMENT_SIZE((byte) 0x05),
/**
* Protocol control message 6
* The client or the server sends this message to update the output
* bandwidth of the peer. The output bandwidth value is the same as the
* window size for the peer.
* Also known as ClientBW ("client bandwidth") in some RTMP implementations.
*/
SET_PEER_BANDWIDTH((byte) 0x06),
/**
* RTMP audio packet (0x08)
* The client or the server sends this message to send audio data to the peer.
*/
AUDIO((byte) 0x08),
/**
* RTMP video packet (0x09)
* The client or the server sends this message to send video data to the peer.
*/
VIDEO((byte) 0x09),
/**
* RTMP message type 0x0F
* The client or the server sends this message to send Metadata or any
* user data to the peer. Metadata includes details about the data (audio, video etc.)
* like creation time, duration, theme and so on.
* This is the AMF3-encoded version.
*/
DATA_AMF3((byte) 0x0F),
/**
* RTMP message type 0x10
* A shared object is a Flash object (a collection of name value pairs)
* that are in synchronization across multiple clients, instances, and
* so on.
* This is the AMF3 version: kMsgContainerEx=16 for AMF3.
*/
SHARED_OBJECT_AMF3((byte) 0x10),
/**
* RTMP message type 0x11
* Command messages carry the AMF-encoded commands between the client
* and the server.
* A command message consists of command name, transaction ID, and command object that
* contains related parameters.
* This is the AMF3-encoded version.
*/
COMMAND_AMF3((byte) 0x11),
/**
* RTMP message type 0x12
* The client or the server sends this message to send Metadata or any
* user data to the peer. Metadata includes details about the data (audio, video etc.)
* like creation time, duration, theme and so on.
* This is the AMF0-encoded version.
*/
DATA_AMF0((byte) 0x12),
/**
* RTMP message type 0x14
* Command messages carry the AMF-encoded commands between the client
* and the server.
* A command message consists of command name, transaction ID, and command object that
* contains related parameters.
* This is the common AMF0 version, also known as INVOKE in some RTMP implementations.
*/
COMMAND_AMF0((byte) 0x14),
/**
* RTMP message type 0x13
* A shared object is a Flash object (a collection of name value pairs)
* that are in synchronization across multiple clients, instances, and
* so on.
* This is the AMF0 version: kMsgContainer=19 for AMF0.
*/
SHARED_OBJECT_AMF0((byte) 0x13),
/**
* RTMP message type 0x16
* An aggregate message is a single message that contains a list of sub-messages.
*/
AGGREGATE_MESSAGE((byte) 0x16);
private final byte value;
public static MessageType valueOf(byte b) {
for( MessageType c : values() ) {
if( c.value == b ) return c;
}
log.warn("gosh im tired: {}", b);
return MessageType.ABORT;
}
}
}

View File

@ -7,6 +7,8 @@ import org.springframework.context.annotation.Configuration;
@Data
@Configuration
public class ServerConfig {
@Value("${srv.oldMode}") private Boolean oldMode;
@Value("${srv.publicDomain}") private String publicDomain;
@Value("${srv.rtmpPort}") private Integer gameServerPort;
@Value("${srv.resPathSWF}") private String defaultResourcesPath;
@Value("${srv.basePathSWF}") private String defaultBasePath;

View File

@ -0,0 +1,337 @@
package com.alterdekim.game.controller;
import com.alterdekim.game.component.GameServer;
import com.alterdekim.game.component.NativeDao;
import com.alterdekim.game.component.StartUpListener;
import com.alterdekim.game.component.game.ClubAccessType;
import com.alterdekim.game.component.game.PlayerProperties;
import com.alterdekim.game.component.game.PlayerPropertyType;
import com.alterdekim.game.component.game.RoleFlags;
import com.alterdekim.game.component.game.avatar.GoodClothType;
import com.alterdekim.game.component.game.inventory.InventoryItem;
import com.alterdekim.game.controller.result.api.ApiResult;
import com.alterdekim.game.controller.result.api.PreloaderResult;
import com.alterdekim.game.controller.result.api.PromotionBannerResult;
import com.alterdekim.game.controller.result.api.PromotionResult;
import com.alterdekim.game.entity.*;
import com.alterdekim.game.repository.AvatarInventoryRepository;
import com.alterdekim.game.service.*;
import com.alterdekim.game.utils.DateUtils;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("/api")
public class ApiController {
@Autowired
private Environment env;
@Autowired
private NativeDao nativeDao;
@Autowired
private StartUpListener startUpListener;
@Autowired
private GameServer gameServer;
@Autowired
private UserService userService;
@Autowired
private PreloaderService preloaderService;
@Autowired
private PromotionService promotionService;
@Autowired
private PromotionBannerService promotionBannerService;
@Autowired
private LocationService locationService;
@Autowired
private GoodsService goodsService;
@Autowired
private MRService mrService;
@Autowired
private MRTService mrtService;
@Autowired
private TRService trService;
@Autowired
private AvatarInventoryRepository avatarInventoryRepository;
@PostMapping("/delete_row")
public ResponseEntity deleteRow(@RequestParam("table") APITable table, @RequestParam("row") Long rowId) {
switch (table) {
case Preloaders -> preloaderService.removeById(rowId);
case Promotions -> promotionService.removeById(rowId);
case Banners -> promotionBannerService.removeById(rowId);
case Locations -> locationService.removeById(rowId);
case LocationObjects -> locationService.removeObjectById(rowId);
}
return ResponseEntity.ok().build();
}
@PostMapping("/update_table")
public ResponseEntity updateRow(@RequestParam("table") APITable table,
@RequestParam("column") String column,
@RequestParam("id") Long id,
@RequestParam("val") Boolean val) {
if( column.matches("[^a-zA-Z]") || id < 1 ) return ResponseEntity.badRequest().build();
nativeDao.updateTable(table.getVal(), column, val, id);
return ResponseEntity.noContent().build();
}
@RequestMapping(value = "/get_entity_info", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, String>> getEntityInfo(@RequestParam("table") APITable table) {
Map<String, String> m = new HashMap<>();
for( Field f : table.getCl().getDeclaredFields() ) {
m.put(f.getName(), f.getType().getSimpleName());
}
return ResponseEntity.ok(m);
}
@Getter
@AllArgsConstructor
public enum APITable {
Preloaders("preloaders", Preloader.class, StaticController.PanelSection.Preloaders),
Promotions("promotions", Promotion.class, StaticController.PanelSection.Preloaders),
Banners("promotion_banners", PromotionBanner.class, StaticController.PanelSection.Preloaders),
Locations("locations", Location.class, StaticController.PanelSection.Locations),
LocationObjects("location_objects",LocationObjectInstance .class, StaticController.PanelSection.Locations),
Users("users", User.class, StaticController.PanelSection.Users);
private final String val;
private final Class<?> cl;
private final StaticController.PanelSection section;
}
@GetMapping("/get_dashboard_logs")
public ResponseEntity<String> getLogs() {
try {
Path logFile = Paths.get(env.getProperty("logging.file.name"));
RandomAccessFile file = new RandomAccessFile(logFile.toFile(), "r");
int n = 2048;
file.seek(logFile.toFile().length() - n);
byte[] b = new byte[n];
file.read(b, 0, n);
return ResponseEntity.ok(new String(b));
} catch (IOException e) {
log.error("getLogs error: {}", e.getMessage());
return ResponseEntity.badRequest().build();
}
}
@GetMapping("/get_uptime")
public ResponseEntity<String> getUpTime() {
return ResponseEntity.ok(
DateUtils.prettyPrint(Duration.of(System.currentTimeMillis() - startUpListener.getStartTime(), ChronoUnit.MILLIS))
);
}
@GetMapping("/get_players_online")
public ResponseEntity<Integer> getPlayersOnline() {
return ResponseEntity.ok(gameServer.getPlayersCount());
}
@GetMapping("/get_users_count")
public ResponseEntity<Long> getUsersCount() {
return ResponseEntity.ok(userService.getUsersCount());
}
@RequestMapping(value = "/get_entity_rows", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Object>> getEntityRows(@RequestParam("entity") APITable table) {
var r = switch (table) {
case Preloaders -> preloaderService.getAll();
case Promotions -> promotionService.getAll();
case Banners -> promotionBannerService.getAll();
case Locations -> locationService.getAll();
case LocationObjects -> locationService.getAllLocationObjects();
case Users -> userService.getAll();
};
return ResponseEntity.ok(
r
.stream()
.map(ApiResult::toAPIResult)
.collect(Collectors.toList())
);
}
@RequestMapping(value = "/reset_user_property", method = RequestMethod.POST)
public ResponseEntity resetUserProperty(@RequestParam("user_id") Integer userId, @RequestParam("entry_name") String entryName) {
PlayerProperties property = PlayerProperties.valueOf(entryName);
userService.removeUserProperty(userId, property);
userService.getUserInitInfoByUserId(userId);
return ResponseEntity.ok().build();
}
@RequestMapping(value = "/edit_user_property", method = RequestMethod.POST)
public ResponseEntity editUserProperty(@RequestParam("user_id") Integer userId,
@RequestParam("entry_name") String entryName,
@RequestParam("entry_value") String entryValue) {
PlayerProperties property = PlayerProperties.valueOf(entryName);
Object val = switch (property.getValueType()) {
case Enum -> {
if( property == PlayerProperties.RoleFlags ) {
yield RoleFlags.valueOf(entryValue);
}
yield ClubAccessType.valueOf(entryValue);
}
case Boolean -> Boolean.parseBoolean(entryValue);
default -> Integer.parseInt(entryValue);
};
userService.pushUserProperty(userId, property, val);
return ResponseEntity.ok().build();
}
@RequestMapping(value = "/get_user_properties", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<UserPropertyResult>> getUserProperties(@RequestParam("id") Integer userId) {
List<UserPropertyResult> results = new LinkedList<>();
for( PlayerProperties property : PlayerProperties.values() ) {
Object value = userService.findUserProperty(userId, property).orElse(null);
if( value == null ) continue;
results.add(new UserPropertyResult(property.getValueType(), property.name(), value));
}
return ResponseEntity.ok(results);
}
@RequestMapping(value = "/get_goods", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<GoodResult>> getGoods() {
List<GoodResult> results = new LinkedList<>();
for( Good good : goodsService.getAll() ) {
GoodResult result = new GoodResult();
long goodId = good.getId();
result.setGoodId(goodId);
Integer iconId = -good.getMRId();
Integer trId = good.getTRId();
var icon = mrService.findById(iconId.longValue());
if( icon.isPresent() ) {
String url = mrtService.findById(icon.get().getTId().longValue()).getVal() + icon.get().getUrl();
result.setUrl(url);
}
var name = trService.findById(trId.longValue());
if( name.isPresent() ) {
String text = name.get().getH();
result.setName(text);
}
results.add(result);
}
return ResponseEntity.ok(results);
}
@RequestMapping(value = "/get_avatar_inventory", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<GoodResult>> getInventory(@RequestParam("id") Integer userId) {
List<GoodResult> results = new LinkedList<>();
List<InventoryItem> items = Arrays.stream(GoodClothType.values())
.map(type -> this.avatarInventoryRepository.findInventoryItems(userId, type))
.flatMap(Collection::stream)
.collect(Collectors.toList());
for( InventoryItem avatarInventory : items) {
var og = goodsService.findById(avatarInventory.getId());
if( og.isPresent() ) {
var good = og.get();
GoodResult result = new GoodResult();
long goodId = good.getId();
result.setGoodId(goodId);
Integer iconId = -good.getMRId();
Integer trId = good.getTRId();
var icon = mrService.findById(iconId.longValue());
if (icon.isPresent()) {
String url = mrtService.findById(icon.get().getTId().longValue()).getVal() + icon.get().getUrl();
result.setUrl(url);
}
var name = trService.findById(trId.longValue());
if (name.isPresent()) {
String text = name.get().getH();
result.setName(text);
}
results.add(result);
}
}
return ResponseEntity.ok(results);
}
@Setter
@NoArgsConstructor
public static class GoodResult {
@JsonProperty
private String url;
@JsonProperty
private Long goodId;
@JsonProperty
private String name;
}
@AllArgsConstructor
public static class UserPropertyResult {
@JsonProperty
private PlayerPropertyType type;
@JsonProperty
private String name;
@JsonProperty
private Object value;
}
@RequestMapping(value = "/add_row", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AddEntryResponse> addSpecificRow(HttpServletRequest httpServletRequest) {
if( !httpServletRequest.getParameterMap().containsKey("table") ) return ResponseEntity.badRequest().build();
try {
APITable table = APITable.valueOf(httpServletRequest.getParameterMap().get("table")[0]);
List<Field> fields = Arrays.stream(table.getCl().getDeclaredFields())
.filter(f -> httpServletRequest.getParameterMap().containsKey(f.getName()))
.collect(Collectors.toList());
Map<String, String> vals = new HashMap<>();
for (Field f : fields) {
String val = httpServletRequest.getParameterMap().get(f.getName())[0];
val = switch (f.getType().getSimpleName()) {
case "String" -> "'" + val + "'";
case "Boolean" -> val.equals("true") ? "1" : "0";
default -> val;
};
vals.put(f.getName(), val);
}
nativeDao.insertEntity(table.getVal(), vals);
return ResponseEntity.ok(new AddEntryResponse(table.getSection().name()));
} catch (Exception e) {
log.error("addEntry error: {}", e.getMessage());
}
return ResponseEntity.internalServerError().build();
}
@AllArgsConstructor
private class AddEntryResponse {
@JsonProperty
private String section;
}
}

View File

@ -1,7 +1,13 @@
package com.alterdekim.game.controller;
import com.alterdekim.game.config.ServerConfig;
import com.alterdekim.game.controller.result.async.*;
import com.alterdekim.game.controller.result.async.old.ResourcesResult;
import com.alterdekim.game.controller.result.async.old.ServerActionCDataOld;
import com.alterdekim.game.controller.result.async.old.ServerActionMRTS;
import com.alterdekim.game.controller.result.async.old.ServerActionResultOld;
import com.alterdekim.game.entity.User;
import com.alterdekim.game.repository.MagicAbilityRepository;
import com.alterdekim.game.security.AuthenticationUtil;
import com.alterdekim.game.service.*;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
@ -18,6 +24,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@ -48,9 +55,32 @@ public class AsyncController {
@Autowired
private UserService userService;
@Autowired
private ServerConfig serverConfig;
@Autowired
private MRService mrService;
@Autowired
private TRService trService;
@Autowired
private ROService roService;
@Autowired
private OnlineStatusService onlineStatusService;
@Autowired
private MAService maService;
@Autowired
private MRTService mrtService;
@PostMapping("/async/Ping")
@ResponseBody
public ResponseEntity<String> ping() {
User user = AuthenticationUtil.authProfile(userService).get();
onlineStatusService.setOnlineFor(user.getId());
return ResponseEntity.ok("<response isPong=\"true\" />");
}
@ -58,16 +88,26 @@ public class AsyncController {
@ResponseBody
public ResponseEntity<String> serverAction() {
try {
//User user = AuthenticationUtil.authProfile(userService).orElse(userService.findByUsername("jerk"));
if( !serverConfig.getOldMode() ) {
return newMode();
}
return oldMode();
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
}
return ResponseEntity.noContent().build();
}
private ResponseEntity<String> oldMode() throws JsonProcessingException {
User user = AuthenticationUtil.authProfile(userService).get();
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
xmlMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
ServerActionResult serverActionResult = new ServerActionResult();
serverActionResult.setSn_status(new SnStatus(false));
serverActionResult.setUser_name(new UserName(user.getUsername()));
ServerActionResultOld serverActionResult = new ServerActionResultOld();
serverActionResult.setMagicAbilities(maService.getAll());
serverActionResult.setSnStatus(new SnStatus(false));
serverActionResult.setUsername(new UserName(user.getUsername()));
serverActionResult.setFlags(new Flags(true, 13));
serverActionResult.setRequests(new Grants(0));
serverActionResult.setGrants(new Grants(0));
@ -85,14 +125,86 @@ public class AsyncController {
items.add(new ConfigItem(11, ServerActionConfigType.SnId, "1", "number"));
items.add(new ConfigItem(12, ServerActionConfigType.AutoServerSelectionAllowed, "0", "bool"));
List<ServerItem> s_items = new ArrayList<>();
s_items.add(new ServerItem(1, 202, 5, "rtmp://localhost:8888/shararam", 0, 1, 5, 5.1));
s_items.add(new ServerItem(1, 202, 5, "rtmp://"+serverConfig.getPublicDomain()+":"+serverConfig.getGameServerPort()+"/shararam", 0, 1, 5, 5.1));
serverActionResult.setPhone(new PhoneMessages(phoneMessageService.getAllPhoneMessages()));
serverActionResult.setPhone(new PhoneMessages(phoneMessageService.getAllByReceiverId(user.getId())));
serverActionResult.setMiniquest(miniquestService.getAllMiniquests());
serverActionResult.setPostcard(new PostcardMessages(postcardService.getAllPostcards()));
serverActionResult.setPreloader(preloaderService.getAllPreloaders());
serverActionResult.setPromotion(promotionService.getAllPromotions());
serverActionResult.setPromotion_banner(promotionBannerService.getAllPromotionBanners());
serverActionResult.setPostcard(new PostcardMessages(postcardService.getAllPostcardsOfUser(user.getId())));
serverActionResult.setPreloader(preloaderService.getSelected());
serverActionResult.setPromotion(promotionService.getSelected());
serverActionResult.setPromotionBanners(promotionBannerService.getSelected());
List<Tutorial> tutorials = new ArrayList<>();
tutorials.add(new Tutorial(-1, 1));
tutorials.add(new Tutorial(1, 1));
tutorials.add(new Tutorial(2, 1));
tutorials.add(new Tutorial(3, 1));
tutorials.add(new Tutorial(4, 1));
tutorials.add(new Tutorial(5, 1));
serverActionResult.setTutorial(tutorials);
serverActionResult.setResources(new ResourcesResult(mrService.getAll(), trService.getAll(), roService.getAll()));
var config = new ServerActionConfig(items);
var system = new ServerActionSystem(1, "cache/resources.swf"); // swf/cache/rus/resources[19].swf
ServerActionUser userdata = null;
ServerActionServers servers = null;
if( !user.getIsBanned() ) {
userdata = new ServerActionUser(user.getId(), AuthenticationUtil.getToken(user), AuthenticationUtil.getToken(user), 2, null, null);
servers = new ServerActionServers(s_items);
} else {
userdata = new ServerActionUser(user.getId(), null, null, 0, LocalDateTime.now(), 162L);
}
List<ServerActionCData> cdatas = new ArrayList<>();
cdatas.add(userdata);
cdatas.add(config);
cdatas.add(system);
cdatas.add(servers);
cdatas.add(new ServerActionMRTS(mrtService.getAll()));
//serverActionResult.setCdata(new ServerActionCDataOld(userdata, config, system, servers, mrtService.getAll()));
log.info("serverActionResult: {}", serverActionResult);
serverActionResult.setCdata(cdatas);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_XML)
.body(xmlMapper.writeValueAsString(serverActionResult));
}
private ResponseEntity<String> newMode() throws JsonProcessingException {
User user = AuthenticationUtil.authProfile(userService).get();
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
xmlMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
ServerActionResult serverActionResult = new ServerActionResult();
serverActionResult.setSnStatus(new SnStatus(false));
serverActionResult.setUsername(new UserName(user.getUsername()));
serverActionResult.setFlags(new Flags(true, 13));
serverActionResult.setRequests(new Grants(0));
serverActionResult.setGrants(new Grants(0));
List<ConfigItem> items = new ArrayList<>();
items.add(new ConfigItem(1, ServerActionConfigType.IsPreloaderEnabled, "1", "bool")); // play with it
items.add(new ConfigItem(2, ServerActionConfigType.SynchronizeAvatarRotation, "1", "bool"));
items.add(new ConfigItem(3, ServerActionConfigType.InitialVolumeValue, "30", "number"));
items.add(new ConfigItem(4, ServerActionConfigType.IsStartupHomeLocation, "0", "bool"));
items.add(new ConfigItem(5, ServerActionConfigType.AccessRoleFlags, "0", "number"));
items.add(new ConfigItem(6, ServerActionConfigType.IsInternational, "0", "bool")); // play with it
items.add(new ConfigItem(7, ServerActionConfigType.TypeWeapon, "1", "number"));
items.add(new ConfigItem(8, ServerActionConfigType.StatisticsSendInterval, "300", "number"));
items.add(new ConfigItem(9, ServerActionConfigType.SwfVersion, "", "string"));
items.add(new ConfigItem(10, ServerActionConfigType.LanguageId, "1", "number")); // play with it
items.add(new ConfigItem(11, ServerActionConfigType.SnId, "1", "number"));
items.add(new ConfigItem(12, ServerActionConfigType.AutoServerSelectionAllowed, "0", "bool"));
List<ServerItem> s_items = new ArrayList<>();
s_items.add(new ServerItem(1, 202, 5, "rtmp://"+serverConfig.getPublicDomain()+":"+serverConfig.getGameServerPort()+"/shararam", 0, 1, 5, 5.1));
serverActionResult.setPhone(new PhoneMessages(phoneMessageService.getAllByReceiverId(user.getId())));
serverActionResult.setMiniquest(miniquestService.getAllMiniquests());
serverActionResult.setPostcard(new PostcardMessages(postcardService.getAllPostcardsOfUser(user.getId())));
serverActionResult.setPreloader(preloaderService.getSelected());
serverActionResult.setPromotion(promotionService.getSelected());
serverActionResult.setPromotionBanners(promotionBannerService.getSelected());
List<Tutorial> tutorials = new ArrayList<>();
@ -107,15 +219,15 @@ public class AsyncController {
List<ServerActionCData> cdatas = new ArrayList<>();
cdatas.add(new ServerActionConfig(items));
cdatas.add(new ServerActionSystem(1, "cache/resources.swf")); // swf/cache/rus/resources[19].swf
cdatas.add(new ServerActionUser(user.getId(), AuthenticationUtil.getToken(user), AuthenticationUtil.getToken(user), 2));
if( !user.getIsBanned() ) {
cdatas.add(new ServerActionUser(user.getId(), AuthenticationUtil.getToken(user), AuthenticationUtil.getToken(user), 2, null, null));
cdatas.add(new ServerActionServers(s_items));
} else {
cdatas.add(new ServerActionUser(user.getId(), null, null, 0, LocalDateTime.now(), 162L));
}
serverActionResult.setCdata(cdatas);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_XML)
.body(xmlMapper.writeValueAsString(serverActionResult));
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
}
return ResponseEntity.noContent().build();
}
}

View File

@ -21,7 +21,9 @@ public class FileServerController {
@Autowired
private FileSystemStorageService storageService;
@RequestMapping(value = {"/file/**"}, method = RequestMethod.GET)
public static final String URL_PATH = "file";
@RequestMapping(value = "/"+URL_PATH+"/**", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<byte[]> serveFile(HttpServletRequest request) {
try {
@ -32,6 +34,7 @@ public class FileServerController {
case "css" -> MediaType.parseMediaType("text/css");
case "_js" -> MediaType.parseMediaType("text/javascript");
case "img" -> MediaType.parseMediaType("image/jpeg");
case "svg" -> MediaType.parseMediaType("image/svg+xml");
default -> MediaType.TEXT_PLAIN;
}).body(Files.readAllBytes(path));
} catch (Exception e) {

View File

@ -1,11 +1,15 @@
package com.alterdekim.game.controller;
import com.alterdekim.game.component.ReferenceLoader;
import com.alterdekim.game.component.game.AvatarInventoryType;
import com.alterdekim.game.controller.result.signup.*;
import com.alterdekim.game.entity.AvatarInventory;
import com.alterdekim.game.entity.Role;
import com.alterdekim.game.entity.User;
import com.alterdekim.game.repository.UserRepository;
import com.alterdekim.game.security.AuthenticationUtil;
import com.alterdekim.game.service.AvatarInventoryService;
import com.alterdekim.game.service.GoodsService;
import com.alterdekim.game.service.IncompatibleService;
import com.alterdekim.game.service.UserService;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
@ -27,10 +31,15 @@ import java.util.Base64;
import java.util.List;
import java.util.Optional;
import static com.alterdekim.game.utils.GameUtils.EmptyGoodId;
@Slf4j
@Controller
public class SignUpController {
@Autowired
private ReferenceLoader referenceLoader;
@Autowired
private AvatarInventoryService avatarInventoryService;
@ -40,6 +49,9 @@ public class SignUpController {
@Autowired
private UserService userService;
@Autowired
private GoodsService goodsService;
@PostMapping("/ConstructorACHandler.ashx")
public ResponseEntity<String> avatarController() {
@ -91,19 +103,24 @@ public class SignUpController {
return ResponseEntity.badRequest().body("bad_credentials_format");
}
long userId = userService.saveUser(username, password);
int userId = userService.saveUser(username, password, Role.RoleType.RoleUser);
avatarInventoryService.addPhoneToInventory(userId, 1L);
avatarInventoryService.addBackgroundToInventory(userId, 339L);
avatarInventoryService.addGoodToInventory(new AvatarInventory(referenceLoader.getUserReference(userId), 102L, true, AvatarInventoryType.House));
try {
av.getInventory()
.stream()
.filter(i -> i.getID() != 98)
.map(i -> new AvatarInventory(userId, i.getID().longValue(), true, AvatarInventoryType.Clothes))
.filter(i -> i.getID() != EmptyGoodId.intValue())
.map(i -> new AvatarInventory(referenceLoader.getUserReference(userId), i.getID().longValue(), true, AvatarInventoryType.fromGoodId(goodsService, i.getID()), 0))
.forEach(i -> avatarInventoryService.addGoodToInventory(i));
av.getBodyParts()
.stream()
.filter(i -> i.getID() != 98)
.map(i -> new AvatarInventory(userId, i.getID().longValue(), true, AvatarInventoryType.BodyParts, i.getColor() == null ? 0 : i.getColor()))
.filter(i -> i.getID() != EmptyGoodId.intValue())
.map(i -> new AvatarInventory(referenceLoader.getUserReference(userId), i.getID().longValue(), true, AvatarInventoryType.BodyParts, i.getColor() == null ? 0 : i.getColor()))
.forEach(i -> avatarInventoryService.addGoodToInventory(i));
} catch (Exception e) {
userService.removeUser(userId);

View File

@ -1,42 +1,126 @@
package com.alterdekim.game.controller;
import com.alterdekim.game.component.ReferenceLoader;
import com.alterdekim.game.component.game.AvatarInventoryType;
import com.alterdekim.game.config.ServerConfig;
import com.alterdekim.game.entity.AvatarInventory;
import com.alterdekim.game.entity.Role;
import com.alterdekim.game.entity.User;
import com.alterdekim.game.security.AuthenticationUtil;
import com.alterdekim.game.service.AvatarInventoryService;
import com.alterdekim.game.service.GoodsService;
import com.alterdekim.game.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import static com.alterdekim.game.controller.FileServerController.URL_PATH;
@Slf4j
@Controller
public class StaticController {
@Autowired
private ServerProperties serverProperties;
@Autowired
private ServerConfig serverConfig;
@Autowired
private UserService userService;
@Autowired
private ReferenceLoader referenceLoader;
@Autowired
private GoodsService goodsService;
@GetMapping("/main")
public String mainPage() {
public String mainPage(Model model) {
User user = AuthenticationUtil.authProfile(userService).get();
if( user.getRoles().stream().anyMatch(r -> r.getName() == Role.RoleType.RoleAdmin) ) return "redirect:/panel";
model.addAttribute("flashVars", "game_server=http%3A%2F%2F"+serverConfig.getPublicDomain()+"%3A"+serverProperties.getPort()+"%2F&url_path_server=http%3A%2F%2F"+serverConfig.getPublicDomain()+"%3A"+serverProperties.getPort()+"%2F&portal_url=http%3A%2F%2F"+serverConfig.getPublicDomain()+"%2F&manual_server_selection=1&start_step=0");
return "main";
}
@GetMapping("/")
public String defPage() {
public String defPage(Model model) {
if( AuthenticationUtil.authProfile(userService).isPresent() ) return "redirect:/main";
model.addAttribute("flashVars", "game_server=http://"+serverConfig.getPublicDomain()+":"+serverProperties.getPort()+"/&amp;url_path_server=http://"+serverConfig.getPublicDomain()+":"+serverProperties.getPort()+"/&amp;is_new_user=1");
model.addAttribute("flashVars_", "game_server=http://"+serverConfig.getPublicDomain()+":"+serverProperties.getPort()+"/&amp;url_path_server=http://"+serverConfig.getPublicDomain()+":"+serverProperties.getPort()+"/&amp;is_new_user=1");
return "index";
}
@GetMapping("/crossdomain.xml")
public ResponseEntity<String> crossdomain() {
return ResponseEntity.ok().contentType(MediaType.APPLICATION_XML).body("<?xml version=\"1.0\" ?>\n" +
"<cross-domain-policy>\n" +
" <site-control permitted-cross-domain-policies=\"all\"/>\n" +
" <allow-access-from domain=\"*\"/>\n" +
" <allow-http-request-headers-from domain=\"*\" headers=\"*\"/>\n" +
"</cross-domain-policy>\n");
@GetMapping("/panel")
public String panel(Model model, @RequestParam(value = "section", defaultValue = "Dashboard") PanelSection section, @RequestParam(value = "table", required = false) ApiController.APITable table) {
model.addAttribute("section", section.name());
if( table != null ) model.addAttribute("table_add", table.name());
model.addAttribute("script", "/" + URL_PATH + "/_js/" + section.name().toLowerCase() + ".js");
return "panel";
}
@GetMapping("/panel_user")
public String panelUser(Model model, @RequestParam(value = "id", defaultValue = "1") Integer userId) {
model.addAttribute("user_id", userId);
model.addAttribute("user_name", userService.getUsernameById(userId).get());
model.addAttribute("inventory_link", "/panel_inventory?id="+userId);
return "panel_user";
}
@GetMapping("/panel_inventory")
public String panelInventory(Model model, @RequestParam(value = "id", defaultValue = "1") Integer userId) {
model.addAttribute("user_id", userId);
model.addAttribute("user_name", "Inventory of " + userService.getUsernameById(userId).get());
return "panel_inventory";
}
@PostMapping("/panel_inventory")
public String panelInventory(Model model, @RequestParam(value = "id", defaultValue = "1") Integer userId, @RequestParam(value = "good_id") Long goodId) {
model.addAttribute("user_id", userId);
model.addAttribute("user_name", "Inventory of " + userService.getUsernameById(userId).get());
userService.pushToInventory(userId, AvatarInventoryType.fromGoodId(goodsService, goodId), goodId);
return "redirect:/panel_inventory?id="+userId;
}
@GetMapping("/goods")
public String goodsPage() {
return "goods";
}
public enum PanelSection {
Dashboard,
Locations,
Games,
Preloaders,
Users,
Banlist,
Cache,
Goods,
Items,
Actions,
Support,
Add,
Settings
}
}

View File

@ -0,0 +1,5 @@
package com.alterdekim.game.controller.result.api;
public interface ApiResult {
Object toAPIResult();
}

View File

@ -0,0 +1,39 @@
package com.alterdekim.game.controller.result.api;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class LocationObjectInstanceResult {
@JsonProperty
private Long id;
@JsonProperty
private Integer objectTypeId;
@JsonProperty
private Integer objectId;
@JsonProperty
private Integer objectReferenceId;
@JsonProperty
private Long mediaResourceId;
@JsonProperty
private Long locationId;
@JsonProperty
private Double x;
@JsonProperty
private Double y;
@JsonProperty
private String options;
@JsonProperty
private String comment;
}

View File

@ -0,0 +1,32 @@
package com.alterdekim.game.controller.result.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.Column;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class LocationResult {
@JsonProperty
private Long id;
@JsonProperty
private Long locationId;
@JsonProperty
private Long mediaResourceId;
@JsonProperty
private Double x;
@JsonProperty
private Double y;
@JsonProperty
private String name;
@JsonProperty
private Boolean isDefault;
@JsonProperty
private Boolean isEnabled;
}

View File

@ -0,0 +1,20 @@
package com.alterdekim.game.controller.result.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class PreloaderResult {
@JsonProperty
private Long id;
@JsonProperty
private Integer mrId;
@JsonProperty
private Integer showTime;
@JsonProperty
private Boolean isSelected;
}

View File

@ -0,0 +1,19 @@
package com.alterdekim.game.controller.result.api;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.persistence.Column;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class PromotionBannerResult {
@JsonProperty
private Long id;
@JsonProperty
private Integer mrId;
@JsonProperty
private Boolean isSelected;
}

View File

@ -0,0 +1,25 @@
package com.alterdekim.game.controller.result.api;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class PromotionResult {
@JsonProperty
private Long id;
@JsonProperty
private Integer mrId;
@JsonProperty
private String state;
@JsonProperty
private Boolean isSelected;
}

View File

@ -0,0 +1,16 @@
package com.alterdekim.game.controller.result.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class UserResult {
@JsonProperty
private Integer id;
@JsonProperty
private String username;
@JsonProperty
private Boolean isBanned;
}

View File

@ -1,6 +1,5 @@
package com.alterdekim.game.controller.result.async;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@ -8,16 +7,16 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
@JsonRootName(value = "item")
public class ConfigItem {
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer Id;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private ServerActionConfigType Parameter;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private String Value;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private String Type;
@JacksonXmlProperty(isAttribute = true, localName = "Id")
private Integer id;
@JacksonXmlProperty(isAttribute = true, localName = "Parameter")
private ServerActionConfigType parameter;
@JacksonXmlProperty(isAttribute = true, localName = "Value")
private String value;
@JacksonXmlProperty(isAttribute = true, localName = "Type")
private String type;
}

View File

@ -1,7 +1,6 @@
package com.alterdekim.game.controller.result.async;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@ -9,12 +8,10 @@ import lombok.Getter;
@AllArgsConstructor
public class Flags {
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
@JacksonXmlProperty(isAttribute = true, localName = "IsUserDetailsMissing")
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean IsUserDetailsMissing;
private Boolean isUserDetailsMissing;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer EntranceCount;
@JacksonXmlProperty(isAttribute = true, localName = "EntranceCount")
private Integer entranceCount;
}

View File

@ -1,6 +1,5 @@
package com.alterdekim.game.controller.result.async;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -8,7 +7,6 @@ import lombok.Getter;
@AllArgsConstructor
public class Grants {
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer ReceivingCount;
@JacksonXmlProperty(isAttribute = true, localName = "ReceivingCount")
private Integer receivingCount;
}

View File

@ -5,7 +5,6 @@ import com.alterdekim.game.entity.Preloader;
import com.alterdekim.game.entity.Promotion;
import com.alterdekim.game.entity.PromotionBanner;
import com.alterdekim.game.xml.CryptoSerializer;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
@ -24,41 +23,41 @@ import java.util.List;
@JsonRootName(value = "response")
public class ServerActionResult {
@JsonProperty
private SnStatus sn_status;
@JacksonXmlProperty(isAttribute = false, localName = "sn_status")
private SnStatus snStatus;
@JsonProperty
private UserName user_name;
@JacksonXmlProperty(isAttribute = false, localName = "user_name")
private UserName username;
@JsonProperty
@JacksonXmlProperty
private List<Preloader> preloader;
@JsonProperty
@JacksonXmlProperty
private Flags flags;
@JacksonXmlProperty(localName = "tutorial")
@JacksonXmlElementWrapper(useWrapping = true, localName = "tutorial")
private List<Tutorial> tutorial;
@JsonProperty
@JacksonXmlProperty
private Grants grants;
@JsonProperty
@JacksonXmlProperty
private Grants requests;
@JsonProperty
@JacksonXmlProperty
private List<Promotion> promotion;
@JsonProperty
private List<PromotionBanner> promotion_banner;
@JacksonXmlProperty(localName = "promotion_banner")
private List<PromotionBanner> promotionBanners;
@JsonProperty
@JacksonXmlProperty
private PhoneMessages phone;
@JsonProperty
@JacksonXmlProperty
private PostcardMessages postcard;
@JsonProperty
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = true, localName = "miniquest")
private List<Miniquest> miniquest;

View File

@ -16,11 +16,11 @@ import java.util.Date;
@JsonRootName(value = "system")
public class ServerActionSystem extends ServerActionCData {
@JacksonXmlProperty(isAttribute = true)
private Integer RVersion;
@JacksonXmlProperty(isAttribute = true, localName = "RVersion")
private Integer rVersion;
@JacksonXmlProperty(isAttribute = true)
private String RPath;
@JacksonXmlProperty(isAttribute = true, localName = "RPath")
private String rPath;
@JacksonXmlProperty(isAttribute = true, localName = "ServerDate")
public String ServerDate() {

View File

@ -1,19 +1,23 @@
package com.alterdekim.game.controller.result.async;
import com.alterdekim.game.xml.LocalDateTimeSerializer;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
@Setter
@AllArgsConstructor
@NoArgsConstructor
@JsonRootName(value = "user")
public class ServerActionUser extends ServerActionCData {
@JacksonXmlProperty(isAttribute = true)
private Long UserId;
@JacksonXmlProperty(isAttribute = true, localName = "UserId")
private Integer userId;
@JacksonXmlProperty(isAttribute = true)
private String hwId;
@ -21,6 +25,13 @@ public class ServerActionUser extends ServerActionCData {
@JacksonXmlProperty(isAttribute = true)
private String ticketId;
@JacksonXmlProperty(isAttribute = true)
private Integer RoleFlags;
@JacksonXmlProperty(isAttribute = true, localName = "RoleFlags")
private Integer roleFlags;
@JacksonXmlProperty(isAttribute = true, localName = "BanDateExpired")
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime banDateExpired;
@JacksonXmlProperty(isAttribute = true, localName = "BanTextResourceID")
private Long banTextResourceID;
}

View File

@ -1,6 +1,5 @@
package com.alterdekim.game.controller.result.async;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@ -8,28 +7,28 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
@JsonRootName(value = "item")
public class ServerItem {
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer Id;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer TRId;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer RId;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private String RTMPUrl;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer Load;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer FriendsCount;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer ClubsCount;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Double Weight;
@JacksonXmlProperty(isAttribute = true, localName = "Id")
private Integer id;
@JacksonXmlProperty(isAttribute = true, localName = "TRId")
private Integer trId;
@JacksonXmlProperty(isAttribute = true, localName = "RId")
private Integer rId;
@JacksonXmlProperty(isAttribute = true, localName = "RTMPUrl")
private String rtmpUrl;
@JacksonXmlProperty(isAttribute = true, localName = "Load")
private Integer load;
@JacksonXmlProperty(isAttribute = true, localName = "FriendsCount")
private Integer friendsCount;
@JacksonXmlProperty(isAttribute = true, localName = "ClubsCount")
private Integer clubsCount;
@JacksonXmlProperty(isAttribute = true, localName = "Weight")
private Double weight;
}

View File

@ -1,7 +1,6 @@
package com.alterdekim.game.controller.result.async;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
@ -9,8 +8,7 @@ import lombok.Getter;
@AllArgsConstructor
public class SnStatus {
@JsonProperty
@JsonSerialize(using= NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true)
private Boolean IsBinded;
@JacksonXmlProperty(isAttribute = true, localName = "IsBinded")
private Boolean isBinded;
}

View File

@ -1,6 +1,5 @@
package com.alterdekim.game.controller.result.async;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -8,11 +7,9 @@ import lombok.Getter;
@AllArgsConstructor
@Getter
public class Tutorial {
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer Id;
@JacksonXmlProperty(isAttribute = true, localName = "Id")
private Integer id;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private Integer State;
@JacksonXmlProperty(isAttribute = true, localName = "State")
private Integer state;
}

View File

@ -1,13 +1,13 @@
package com.alterdekim.game.controller.result.async;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@ToString
@AllArgsConstructor
public class UserName {
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
private String Value;
@JacksonXmlProperty(isAttribute = true, localName = "Value")
private String value;
}

View File

@ -1,155 +0,0 @@
package com.alterdekim.game.controller.result.async;
import com.alterdekim.game.component.game.ClubAccessType;
import com.alterdekim.game.component.game.RoleFlags;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonRootName(value = "user")
public class UserResult {
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "UserId")
private Long id;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "Name")
private String username;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "LocationServerName")
private String locationServerName;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "RoleFlags")
private RoleFlags roleFlags;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "InstructorLevel")
private Integer instructorLevel;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "MagicLevel")
private Integer magicLevel;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "RaceLevel")
private Integer raceLevel;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "PhoneID")
private Integer phoneID;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "BackgroundID")
private Integer backgroundID;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "UsualTickets")
private Integer usualTickets;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "MagicTickets")
private Integer magicTickets;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "Experience")
private Integer experience;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "Level")
private Integer level;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "PositiveEnergy")
private Integer positiveEnergy;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "VisaId")
private Integer visaId;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "CurrentUseCount")
private Integer currentUseCount;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "LastNewspaperId")
private Integer lastNewspaperId;
@JsonSerialize(using= NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "IsClubPresent")
private Boolean isClubPresent;
@JsonSerialize(using = NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "IsClubLocked")
private Boolean isClubLocked;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "ClubAccessType")
private ClubAccessType clubAccessType;
@JsonSerialize(using= NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "IsMinorSecretAgent")
private Boolean isMinorSecretAgent;
@JsonSerialize(using= NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "HasSnFriends")
private Boolean hasSnFriends;
@JsonSerialize(using= NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "IsHomeLocked")
private Boolean isHomeLocked;
@JsonSerialize(using = NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "IsLimited")
private Boolean isLimited;
@JsonSerialize(using = NumericBooleanSerializer.class)
@JacksonXmlProperty(isAttribute = true, localName = "IsOnline")
private Boolean isOnline;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "CampId")
private Integer campId;
@Column(nullable = false)
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "NiftTotalCount")
private Integer niftTotalCount;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "DateRegistered")
private Date dateRegistered;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "MinsLeft")
private Integer minsLeft;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "TimesUsed")
private Integer timesUsed;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "IsFriend")
private Boolean isFriend;
}

View File

@ -0,0 +1,28 @@
package com.alterdekim.game.controller.result.async.old;
import com.alterdekim.game.entity.MediaResource;
import com.alterdekim.game.entity.ResourceObject;
import com.alterdekim.game.entity.TextResource;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
public class ResourcesResult {
@JacksonXmlProperty(isAttribute = false, localName = "MediaResources")
@JacksonXmlElementWrapper(useWrapping = true, localName = "MediaResources")
private List<MediaResource> mediaResources;
@JacksonXmlProperty(isAttribute = false, localName = "TextResources")
@JacksonXmlElementWrapper(useWrapping = true, localName = "TextResources")
private List<TextResource> textResources;
@JacksonXmlProperty(isAttribute = false, localName = "ResourcesOptions")
@JacksonXmlElementWrapper(useWrapping = true, localName = "ResourcesOptions")
private List<ResourceObject> resourceOptions;
}

View File

@ -0,0 +1,32 @@
package com.alterdekim.game.controller.result.async.old;
import com.alterdekim.game.controller.result.async.ServerActionConfig;
import com.alterdekim.game.controller.result.async.ServerActionServers;
import com.alterdekim.game.controller.result.async.ServerActionSystem;
import com.alterdekim.game.controller.result.async.ServerActionUser;
import com.alterdekim.game.entity.MediaResourcePath;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import java.util.List;
@AllArgsConstructor
public class ServerActionCDataOld {
@JacksonXmlProperty(isAttribute = false, localName = "user")
private ServerActionUser user;
@JacksonXmlProperty(isAttribute = false, localName = "config")
private ServerActionConfig config;
@JacksonXmlProperty(isAttribute = false, localName = "system")
private ServerActionSystem system;
@JacksonXmlProperty(isAttribute = false, localName = "servers")
private ServerActionServers servers;
@JacksonXmlProperty(isAttribute = false, localName = "mrtroot")
@JacksonXmlElementWrapper(useWrapping = true, localName = "mrtroot")
private List<MediaResourcePath> mrtRoot;
}

View File

@ -0,0 +1,23 @@
package com.alterdekim.game.controller.result.async.old;
import com.alterdekim.game.controller.result.async.ServerActionCData;
import com.alterdekim.game.entity.MediaResourcePath;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@JsonRootName(value = "mrtroot")
public class ServerActionMRTS extends ServerActionCData {
@JacksonXmlElementWrapper(useWrapping = false, localName = "mrtroot")
private List<MediaResourcePath> mrtRoot;
}

View File

@ -0,0 +1,71 @@
package com.alterdekim.game.controller.result.async.old;
import com.alterdekim.game.controller.result.async.*;
import com.alterdekim.game.entity.*;
import com.alterdekim.game.xml.CryptoSerializer;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.*;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonRootName(value = "response")
public class ServerActionResultOld {
@JacksonXmlProperty(isAttribute = false, localName = "user_name")
private UserName username;
@JacksonXmlProperty(isAttribute = false, localName = "sn_status")
private SnStatus snStatus;
@JacksonXmlProperty
private List<Preloader> preloader;
@JacksonXmlProperty(localName = "magic_abilities")
@JacksonXmlElementWrapper(useWrapping = true, localName = "magic_abilities")
private List<MagicAbility> magicAbilities;
@JacksonXmlProperty
private Flags flags;
@JacksonXmlProperty(localName = "tutorial")
@JacksonXmlElementWrapper(useWrapping = true, localName = "tutorial")
private List<Tutorial> tutorial;
@JacksonXmlProperty
private Grants grants;
@JacksonXmlProperty
private Grants requests;
@JacksonXmlProperty
private List<Promotion> promotion;
@JacksonXmlProperty(localName = "promotion_banner")
private List<PromotionBanner> promotionBanners;
@JacksonXmlProperty
private PhoneMessages phone;
@JacksonXmlProperty
private PostcardMessages postcard;
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = true, localName = "miniquest")
private List<Miniquest> miniquest;
@JacksonXmlProperty(localName = "resources")
private ResourcesResult resources;
@JacksonXmlProperty(localName = "cdata")
@JsonSerialize(using = CryptoSerializer.class)
@JacksonXmlElementWrapper(useWrapping = false, localName = "cdata")
private List<ServerActionCData> cdata;
}

View File

@ -17,10 +17,10 @@ import java.util.List;
@AllArgsConstructor
@JacksonXmlRootElement(localName = "UserAvatar")
public class SignUpAvatar {
@JsonProperty(value = "BodyParts")
@JacksonXmlProperty(localName = "BodyParts")
@JacksonXmlElementWrapper(useWrapping = true, localName = "BodyParts")
private List<SignUpAvatarBodyPart> BodyParts;
@JsonProperty(value = "Inventory")
@JacksonXmlProperty(localName = "Inventory")
@JacksonXmlElementWrapper(useWrapping = true, localName = "Inventory")
private List<SignUpAvatarInventory> Inventory;
@JacksonXmlProperty(localName = "pixels")

View File

@ -11,10 +11,8 @@ import lombok.*;
@NoArgsConstructor
@ToString
public class SignUpAvatarBodyPart {
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "Color")
private Integer Color;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private Integer ID;
}

View File

@ -12,10 +12,8 @@ import lombok.*;
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
public class SignUpAvatarInventory {
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "ActionID")
private Integer ActionID;
@JsonProperty
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private Integer ID;
}

View File

@ -0,0 +1,34 @@
package com.alterdekim.game.crypto;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@Slf4j
public class HMAC {
private Mac hmacSHA256;
public HMAC() {
try {
this.hmacSHA256 = Mac.getInstance("HmacSHA256");
} catch (SecurityException e) {
log.error("Security exception when getting HMAC", e);
} catch (NoSuchAlgorithmException e) {
log.error("HMAC SHA256 does not exist");
}
}
public byte[] calculateHmacSHA256(byte[] input, byte[] key, int length) {
byte[] output = null;
try {
hmacSHA256.init(new SecretKeySpec(key, 0, length, "HmacSHA256"));
output = hmacSHA256.doFinal(input);
} catch (InvalidKeyException e) {
log.error("Invalid key", e);
}
return output;
}
}

View File

@ -2,10 +2,12 @@ package com.alterdekim.game.entity;
import com.alterdekim.game.component.game.AvatarInventoryType;
import com.alterdekim.game.repository.UserRepository;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.beans.factory.annotation.Autowired;
@Getter
@Setter
@ -16,11 +18,12 @@ import lombok.*;
public class AvatarInventory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
@Column(nullable = false)
private Long userId;
@OneToOne
@JoinColumn(referencedColumnName = "id")
private User user;
@Column(nullable = false)
private Long goodId;
@ -34,15 +37,15 @@ public class AvatarInventory {
@Column(nullable = false)
private Integer color = 0;
public AvatarInventory(Long userId, Long goodId, Boolean isUsed, AvatarInventoryType type) {
this.userId = userId;
public AvatarInventory(User user, Long goodId, Boolean isUsed, AvatarInventoryType type) {
this.user = user;
this.goodId = goodId;
this.isUsed = isUsed;
this.type = type;
}
public AvatarInventory(Long userId, Long goodId, Boolean isUsed, AvatarInventoryType type, Integer color) {
this.userId = userId;
public AvatarInventory(User user, Long goodId, Boolean isUsed, AvatarInventoryType type, Integer color) {
this.user = user;
this.goodId = goodId;
this.isUsed = isUsed;
this.type = type;

View File

@ -1,7 +1,7 @@
package com.alterdekim.game.entity;
import com.alterdekim.game.component.game.BodyPartType;
import com.alterdekim.game.component.game.avatar.BodyPartType;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@ -0,0 +1,47 @@
package com.alterdekim.game.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="house_inventory")
public class HouseInventory {
@jakarta.persistence.Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
@OneToOne
@JoinColumn(referencedColumnName = "id")
private User user;
@Column(nullable = false)
private Long goodId;
@Column(nullable = false)
private Long homeId;
@Column(nullable = false)
private Double x;
@Column(nullable = false)
private Double y;
@Column(nullable = false)
private Integer frame;
public HouseInventory(User user, Long goodId, Long homeId, Double x, Double y, Integer frame) {
this.user = user;
this.goodId = goodId;
this.homeId = homeId;
this.x = x;
this.y = y;
this.frame = frame;
}
}

View File

@ -0,0 +1,32 @@
package com.alterdekim.game.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Entity
@Table(name = "house_locations")
public class HouseLocation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long goodId;
@Column(nullable = false)
private Integer mediaResourceId;
@Column(nullable = false)
private Boolean isDefault;
public HouseLocation(Long goodId, Integer mediaResourceId, Boolean isDefault) {
this.goodId = goodId;
this.mediaResourceId = mediaResourceId;
this.isDefault = isDefault;
}
}

View File

@ -1,5 +1,8 @@
package com.alterdekim.game.entity;
import com.alterdekim.game.controller.result.api.ApiResult;
import com.alterdekim.game.controller.result.api.LocationResult;
import com.alterdekim.game.controller.result.api.PreloaderResult;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -11,7 +14,7 @@ import lombok.RequiredArgsConstructor;
@Getter
@Entity
@Table(name = "locations")
public class Location {
public class Location implements ApiResult {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ -46,4 +49,9 @@ public class Location {
this.isDefault = isDefault;
this.isEnabled = isEnabled;
}
@Override
public LocationResult toAPIResult() {
return new LocationResult(this.id, this.locationId, this.mediaResourceId, this.x, this.y, this.name, this.isDefault, this.isEnabled);
}
}

View File

@ -0,0 +1,79 @@
package com.alterdekim.game.entity;
import com.alterdekim.game.controller.result.api.ApiResult;
import com.alterdekim.game.controller.result.api.LocationObjectInstanceResult;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Table(name = "location_objects")
@Entity
public class LocationObjectInstance implements ApiResult {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private Long id;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectTypeId")
@Column(nullable = false)
private Integer objectTypeId;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectId")
@Column(nullable = false)
private Integer objectId;
@JacksonXmlProperty(isAttribute = true, localName = "AObjectRefId")
@Column(nullable = false)
private Integer objectReferenceId;
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
@Column(nullable = false)
private Long mediaResourceId;
@JsonIgnore
@Column(nullable = false)
private Long locationId;
@JacksonXmlProperty(isAttribute = true, localName = "x")
@Column(nullable = false)
private Double x;
@JacksonXmlProperty(isAttribute = true, localName = "y")
@Column(nullable = false)
private Double y;
@JacksonXmlText
@Column(nullable = false)
private String options;
@JsonIgnore
@Column(nullable = false)
private String comment;
@JacksonXmlProperty(isAttribute = true, localName = "Frame")
private Integer frame;
@Override
public LocationObjectInstanceResult toAPIResult() {
return new LocationObjectInstanceResult(this.id, this.objectTypeId, this.objectId, this.objectReferenceId, this.mediaResourceId, this.locationId, this.x, this.y, this.options, this.comment);
}
public LocationObjectInstance(Integer objectTypeId, Integer objectId, Integer objectReferenceId, Long mediaResourceId, Long locationId, Double x, Double y, String options, String comment) {
this.objectTypeId = objectTypeId;
this.objectId = objectId;
this.objectReferenceId = objectReferenceId;
this.mediaResourceId = mediaResourceId;
this.locationId = locationId;
this.x = x;
this.y = y;
this.options = options;
this.comment = comment;
}
}

View File

@ -4,6 +4,7 @@ import com.alterdekim.flash.decompiler.mapper.FlashClass;
import com.alterdekim.flash.decompiler.mapper.FlashField;
import com.alterdekim.flash.decompiler.mapper.FlashValue;
import com.alterdekim.flash.decompiler.mapper.FlashValueType;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@ -21,26 +22,32 @@ import lombok.*;
public class MagicAbility {
@Id
@FlashValue(type = FlashValueType.Id)
@JacksonXmlProperty(isAttribute = true, localName = "Id")
private Long id;
@Column(nullable = false)
@FlashField(name = "TypeId")
@JacksonXmlProperty(isAttribute = true, localName = "TypeId")
private Integer typeId;
@Column(nullable = true)
@FlashField(name = "duration")
@JacksonXmlProperty(isAttribute = true, localName = "Duration")
private Integer duration;
@Column(nullable = true)
@FlashField(name = "TweenerId")
@JacksonXmlProperty(isAttribute = true, localName = "TweenerId")
private Integer tweenerId;
@Column(nullable = false)
@FlashField(name = "MRId")
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
private Integer mediaResourceId;
@Column(nullable = false)
@FlashField(name = "TRId")
@JacksonXmlProperty(isAttribute = true, localName = "TRId")
private Integer textResourceId;
@Column(nullable = false)
@ -53,5 +60,6 @@ public class MagicAbility {
@Column(nullable = true)
@FlashField(name = "IsMovable")
@JacksonXmlProperty(isAttribute = true, localName = "IsMovable")
private Boolean isMovable;
}

View File

@ -4,6 +4,7 @@ import com.alterdekim.flash.decompiler.mapper.FlashClass;
import com.alterdekim.flash.decompiler.mapper.FlashField;
import com.alterdekim.flash.decompiler.mapper.FlashValue;
import com.alterdekim.flash.decompiler.mapper.FlashValueType;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@ -20,17 +21,21 @@ import lombok.*;
@FlashClass(name = "mr")
public class MediaResource {
@Id
@JacksonXmlProperty(isAttribute = true, localName = "Id")
@FlashValue(type = FlashValueType.Id)
private Long id;
@JacksonXmlProperty(isAttribute = true, localName = "TId")
@FlashField(name = "TId")
@Column(nullable = false)
private Integer tId;
@JacksonXmlProperty(isAttribute = true, localName = "Url")
@FlashField(name = "Url")
@Column(nullable = false)
private String url;
@JacksonXmlProperty(isAttribute = true, localName = "V")
@FlashField(name = "V")
@Column(nullable = true)
private String v;

View File

@ -3,6 +3,7 @@ package com.alterdekim.game.entity;
import com.alterdekim.flash.decompiler.mapper.FlashClass;
import com.alterdekim.flash.decompiler.mapper.FlashValue;
import com.alterdekim.flash.decompiler.mapper.FlashValueType;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@ -19,10 +20,12 @@ import lombok.*;
@FlashClass(name = "mrt")
public class MediaResourcePath {
@Id
@JacksonXmlProperty(isAttribute = true, localName = "Id")
@FlashValue(type = FlashValueType.Id)
private Long id;
@Column(nullable = false)
@FlashValue(type = FlashValueType.Value)
@JacksonXmlProperty(isAttribute = true, localName = "Url")
private String val;
}

View File

@ -0,0 +1,85 @@
package com.alterdekim.game.entity;
import com.alterdekim.flash.decompiler.mapper.FlashValue;
import com.alterdekim.flash.decompiler.mapper.FlashValueType;
import com.alterdekim.game.xml.NumericBooleanSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "minigames")
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MiniGame {
@Id
@JacksonXmlProperty(isAttribute = true, localName = "ID")
private Long id;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "GameName")
private String gameName;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "NameTRId")
private Integer nameTRId;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "TextResourceID")
private Integer textResourceID;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "MediaResourceID")
private Integer mediaResourceID;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "ScoreDivisor")
private Double scoreDivisor;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "AvatarType")
private Integer avatarType;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "IsPromptUsed")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isPromptUsed;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "IsFullscreen")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isFullscreen;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "IsShowPoints")
@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean isShowPoints;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "StartFullTime")
private Long startFullTime;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "StartLackTime")
private Long startLackTime;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "Options")
private String options;
@Column(nullable = false)
@JacksonXmlProperty(isAttribute = true, localName = "Token")
private String token;
@Column(nullable = false)
@JacksonXmlText
private String groups_list;
}

View File

@ -25,38 +25,33 @@ import java.util.Date;
public class Miniquest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty
private Long Id;
@JacksonXmlProperty(localName = "Id")
private Long id;
@JsonIgnore
@Column(nullable = false)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean isTask;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
@JacksonXmlProperty(isAttribute = true, localName = "MiniquestId")
@Column(nullable = false)
private Long MiniquestId;
private Long miniquestId;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
@JacksonXmlProperty(isAttribute = true, localName = "IsPostponed")
@Column(nullable = false)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean IsPostponed;
private Boolean isPostponed;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
@JacksonXmlProperty(isAttribute = true, localName = "IsFinished")
@Column(nullable = false)
@JsonSerialize(using= NumericBooleanSerializer.class)
private Boolean IsFinished;
private Boolean isFinished;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
@JacksonXmlProperty(isAttribute = true, localName = "StartDate")
@Column(nullable = false)
private String StartDate;
private String startDate;
@JsonProperty
@JacksonXmlProperty(isAttribute = true)
@JacksonXmlProperty(isAttribute = true, localName = "Counter")
@Column(nullable = false)
private Integer Counter;
private Integer counter;
}

Some files were not shown because too many files have changed in this diff Show More