Split client code from server

This commit is contained in:
2026-03-20 23:13:27 +01:00
parent eb3910d7ea
commit 1fc21d700e
117 changed files with 850 additions and 762 deletions
+1 -1
View File
@@ -8,7 +8,6 @@ import { fromNow, includes, hasFlag } from '../common/utils';
import {
isAdmin, getCharacterLimit as getCharacterLimitInternal, getSupporterInviteLimit as getSupporterInviteLimitInternal
} from '../common/accountUtils';
import { cleanName } from '../client/clientUtils';
import {
IAccount, IAuth, Account, ID, characterCount as getCharacterCount, findAccount, queryAccount, updateAccount,
FriendRequest, IFriendRequest
@@ -20,6 +19,7 @@ import { isActive, supporterLevel, isPastSupporter } from '../common/adminUtils'
import { IClient } from './serverInterfaces';
import { providers } from './oauth';
import { taskQueue } from './utils/taskQueue';
import { cleanName } from '../common/stringUtils';
export interface SuspiciousCheckers {
isSuspiciousName(name: string): boolean;
+2 -2
View File
@@ -9,7 +9,6 @@ import {
AuthUpdate, PonyCreator, ServerConfig, GameServerSettings, AccountState, AuthDetails, MergeAccountData,
FindAccountQuery, AdminCache, ClearOrignsOptions, ModelTypes, Stats
} from '../common/adminInterfaces';
import { ClientAdminActions, ClientUpdate } from '../client/clientAdminActions';
import { TokenData } from './serverInterfaces';
import { toAccountData, toPonyObjectAdmin } from './serverUtils';
import {
@@ -38,6 +37,7 @@ import { getDuplicateEntries, getAllDuplicatesQuickInfo, getAllDuplicatesWithInf
import { splitAccounts } from './api/merge';
import { removeAuth, assignAuth } from './api/admin-auths';
import { removeFriend, addFriend } from './accountUtils';
import { ClientAdminActionsTemplate, ClientUpdate } from '../common/clientAdminActionsTemplate';
@Socket({
id: 'admin',
@@ -51,7 +51,7 @@ export class AdminServerActions implements IAdminServerActions, SocketServer {
private cache: AdminCache = {};
private subscriptions = new Map<string, Subscription>();
constructor(
private client: ClientAdminActions & ClientExtensions,
private client: ClientAdminActionsTemplate & ClientExtensions,
private server: ServerConfig,
private settings: Settings,
private adminService: AdminService,
+1 -1
View File
@@ -4,7 +4,6 @@ import {
UpdateAccountData, AccountSettings, AccountData, ModAction, EntitiesEditorInfo, EntityNameTypes
} from '../../common/interfaces';
import { isMod } from '../../common/accountUtils';
import { cleanName } from '../../client/clientUtils';
import { toAccountData, toPonyObject, toSocialSite, toPonyObjectFields, toSocialSiteFields } from '../serverUtils';
import {
IAccount, FindAccountSafe, FindAuth, FindAuths, FindCharacters, CountAuths, Auth,
@@ -15,6 +14,7 @@ import * as entities from '../../common/entities';
import { includes, clamp, createValidBirthDate, parseISODate, formatISODate } from '../../common/utils';
import { getAccountAlertMessage } from '../accountUtils';
import { getAge } from '../../common/adminUtils';
import { cleanName } from '../../common/stringUtils';
export type GetAccountCharacters = ReturnType<typeof createGetAccountCharacters>;
export type UpdateAccount = ReturnType<typeof createUpdateAccount>;
+1 -1
View File
@@ -1,6 +1,5 @@
import { PonyObject, PonyInfoNumber } from '../../common/interfaces';
import { CharacterFlags } from '../../common/adminInterfaces';
import { cleanName, validatePonyName } from '../../client/clientUtils';
import { Reporter, LogAccountMessage } from '../serverInterfaces';
import { toPonyObject } from '../serverUtils';
import { isForbiddenName } from '../../common/security';
@@ -12,6 +11,7 @@ import { CHARACTER_SAVING_ERROR, CHARACTER_LIMIT_ERROR } from '../../common/erro
import { decompressPony, compressPony } from '../../common/compressPony';
import { getCharacterLimit } from '../accountUtils';
import { PLAYER_DESC_MAX_LENGTH } from '../../common/constants';
import { cleanName, validatePonyName } from '../../common/stringUtils';
function colorToText(c: number): string {
return c ? colorToHexRGB(c) : '';
+1 -1
View File
@@ -2,7 +2,7 @@
import { readFileAsync, readFileSync } from 'fs';
import { createCanvas as createNodeCanvas, Image } from 'canvas';
import { setup } from '../client/canvasUtils';
import { setup } from '../common/canvasUtils';
export const createCanvas = createNodeCanvas;
+2 -2
View File
@@ -13,10 +13,10 @@ import { ServerEntity, ServerMap, IClient } from './serverInterfaces';
import { pony as ponyEntity, getEntityType } from '../common/entities';
import { PONY_INFO_KEY, SWAP_TIMEOUT } from '../common/constants';
import { decompressPony, compressPony } from '../common/compressPony';
import { canFly, canMagic } from '../client/ponyUtils';
import { canFly, canMagic } from '../common/ponyUtils';
import { canUseTag } from '../common/tags';
import { CounterService } from './services/counter';
import { replaceEmojis } from '../client/emoji';
import { replaceEmojis } from '../common/emoji';
import { setEntityName, pushUpdateEntity } from './entityUtils';
import { saySystem } from './chat';
import { isPonyFlying } from '../common/entityUtils';
+1 -1
View File
@@ -7,7 +7,6 @@ import {
import { trimRepeatedLetters, urlRegexTexts, ipRegexText, urlExceptionRegex } from '../common/filterUtils';
import { parseExpression } from '../common/expressionUtils';
import { filterBadWords } from '../common/swears';
import { cleanMessage } from '../client/clientUtils';
import { parseCommand, getChatPrefix, RunCommand } from './commands';
import { IClient, OnSuspiciousMessage, ServerEntity, OnMessageSettings } from './serverInterfaces';
import { World } from './world';
@@ -17,6 +16,7 @@ import { isFriend } from './services/friends';
import { invalidEnumReturn } from '../common/utils';
import { isWorldPointWithPaddingVisible } from '../common/camera';
import { tileWidth } from '../common/constants';
import { cleanMessage } from '../common/stringUtils';
function isLaugh(message: string): boolean {
return /(^| )(ha(ha)+|he(he)+|ja(ja)+|ха(ха)+|lol|rofl)$/i.test(message);
+2 -2
View File
@@ -4,7 +4,7 @@ import {
} from '../common/interfaces';
import { hasRole } from '../common/accountUtils';
import { butterfly, bat, firefly, cloud, getEntityType, getEntityTypeName } from '../common/entities';
import { emojis } from '../client/emoji';
import { emojis } from '../common/emoji';
import { IClient, ServerMap } from './serverInterfaces';
import { World } from './world';
import { NotificationService } from './services/notification';
@@ -29,11 +29,11 @@ import {
} from './serverMap';
import { PARTY_LIMIT, tileWidth, tileHeight, MAP_LOAD_SAVE_TIMEOUT } from '../common/constants';
import { PartyService } from './services/party';
import { getRegionGlobal } from '../common/worldMap';
import { swapCharacter } from './characterUtils';
import { writeFileAsync } from 'fs';
import { Account } from './db';
import { defaultHouseSave, removeToolbox, restoreToolbox } from './maps/houseMap';
import { getRegionGlobal } from '../common/region';
export interface CommandContext {
world: World;
+1 -1
View File
@@ -4,7 +4,7 @@ import { World } from '../world';
import { timingStart, timingEnd } from '../timing';
import { Rect, CreateEntityMethod, ServerFlags, TileType } from '../../common/interfaces';
import { removeItem, randomPoint } from '../../common/utils';
import { getTile } from '../../common/worldMap';
import { getTile } from '../../common/tileUtils';
interface Plant extends ServerEntity {
plantStage: number;
+1 -1
View File
@@ -6,7 +6,7 @@ import {
import { logger } from './logger';
import { isAdmin } from '../common/accountUtils';
import { FriendData } from '../common/interfaces';
import { replaceEmojis } from '../client/emoji';
import { replaceEmojis } from '../common/emoji';
import { filterForbidden } from './characterUtils';
import { filterName } from '../common/swears';
+2 -1
View File
@@ -9,12 +9,13 @@ import {
isCritter, isDecal, entityInRange, SIT_ON_BOUNDS_WIDTH, SIT_ON_BOUNDS_HEIGHT, SIT_ON_BOUNDS_OFFSET
} from '../common/entityUtils';
import { pushUpdateEntityToRegion } from './serverRegion';
import { getRegion, getRegionGlobal, getTile } from '../common/worldMap';
import { filterName } from '../common/swears';
import { shouldBeFacingRight } from '../common/movementUtils';
import { writeOneEntity, writeOneUpdate } from '../common/encoders/updateEncoder';
import { PONY_TYPE } from '../common/constants';
import { grapesPurple, grapesGreen } from '../common/entities';
import { getTile } from '../common/tileUtils';
import { getRegion, getRegionGlobal } from '../common/region';
export function isEntityShadowed(entity: ServerEntity): entity is ServerEntityWithClient {
return entity.client !== undefined && entity.client.shadowed;
+2 -3
View File
@@ -2,11 +2,10 @@ import { ServerEntity, ServerMap, IClient } from './serverInterfaces';
import { World } from './world';
import { Rect, SignEntityOptions, MessageType, CreateEntityMethod, PonyOptions, Point } from '../common/interfaces';
import { roundPosition } from '../common/positionUtils';
import { getRegionGlobal } from '../common/worldMap';
import { addEntityToRegion, getRegionTiles, removeEntityFromRegion } from './serverRegion';
import * as entities from '../common/entities';
import { updateTileIndices } from '../client/tileUtils';
import { generateRegionCollider } from '../common/region';
import { updateTileIndices } from '../common/tileUtils';
import { generateRegionCollider, getRegionGlobal } from '../common/region';
import { PONY_TYPE, tileWidth, tileHeight } from '../common/constants';
import { sayTo, saySystem } from './chat';
import { setEntityName, updateEntityVelocity, setEntityAnimation } from './entityUtils';
+1 -1
View File
@@ -7,8 +7,8 @@ import { TileType, MapType, MapFlags, EntityState } from '../../common/interface
import { createServerMap, setTile, MapData, saveMap } from '../serverMap';
import { WallController } from '../controllers';
import { resetRegionUpdates } from '../serverRegion';
import { getTile } from '../../common/worldMap';
import { tileHeight, HOUSE_ENTITY_LIMIT } from '../../common/constants';
import { getTile } from '../../common/tileUtils';
export let defaultHouseSave: MapData | undefined = undefined;
+1 -1
View File
@@ -28,7 +28,7 @@ import {
updateEntityOptions, canBoopEntity, findPlayersThetCanBeSitOn, updateEntityState, updateEntityExpression,
sendAction, pushUpdateEntityToClient, fixPosition, isHoldingGrapes
} from './entityUtils';
import { replaceEmojis } from '../client/emoji';
import { replaceEmojis } from '../common/emoji';
import { expression, parseExpression } from '../common/expressionUtils';
import {
canBoopOrKiss, isPonySitting, isPonyStanding, getBoopRect, canStand, isPonyFlying, setPonyState, canSit,
+1 -1
View File
@@ -9,10 +9,10 @@ import { writeRegion, writeUpdate } from '../common/encoders/updateEncoder';
import { toWorldX, toWorldY } from '../common/positionUtils';
import { isRectVisible } from '../common/camera';
import { timingStart, timingEnd } from './timing';
import { getRegion } from '../common/worldMap';
import { logger } from './logger';
import { EntityFlags } from '../common/interfaces';
import { REGION_SIZE } from '../common/constants';
import { getRegion } from '../common/region';
let updatesBuffer = new ArrayBuffer(4096);
let updatesBufferOffset = 0;
+6 -6
View File
@@ -22,8 +22,6 @@ import { rollbarCheckIgnore } from '../common/rollbar';
import { isBanned } from '../common/adminUtils';
import { includes } from '../common/utils';
import { STAMP } from '../generated/hash';
import { ClientActions } from '../client/clientActions';
import { ClientAdminActions } from '../client/clientAdminActions';
import { ServerActions } from './serverActions';
import { AdminServerActions } from './adminServerActions';
import { IAccount, Account } from './db';
@@ -59,6 +57,8 @@ import { InternalAdminApi } from './api/internal-admin';
import { AdminService } from './services/adminService';
import { createEndPoints } from './api/admin';
import { World } from './world';
import { ClientActionsTemplate } from '../common/clientActionsTemplte';
import { ClientAdminActionsTemplate } from '../common/clientAdminActionsTemplate';
function getServiceWorker() {
try {
@@ -255,7 +255,7 @@ if (args.game) {
},
};
const gameSocket = host.socket(ServerActions, ClientActions, createServerActions as any, options);
const gameSocket = host.socket(ServerActions, ClientActionsTemplate, createServerActions as any, options);
const tokens = tokenService(gameSocket);
start(world, server);
@@ -282,12 +282,12 @@ if (args.admin) {
app.use('/api-internal-admin', internal(config, server), wrapApi(server, adminApi));
}
const createClient = (client: ClientAdminActions & ClientExtensions) =>
const createClient = (client: ClientAdminActionsTemplate & ClientExtensions) =>
new AdminServerActions(client, server, settings, adminService!, endPoints!, removedDocument);
const base = '/admin';
const assetsBase = args.standaloneadmin ? '/admin' : '';
const adminSocket = host.socket(AdminServerActions, ClientAdminActions, createClient, socketOptionsBase);
const adminSocket = host.socket(AdminServerActions, ClientAdminActionsTemplate, createClient, socketOptionsBase);
const sendAdminPage = index.admin(production, `${base}/`, assetsBase, 'bootstrap-admin.js', adminSocket);
app.get(`${base}`, ...adminMiddlewares(), sendAdminPage);
@@ -306,7 +306,7 @@ if (args.tools) {
}
if (args.login) {
const socketOptions = createClientOptions(ServerActions, ClientActions, socketOptionsBase);
const socketOptions = createClientOptions(ServerActions, ClientActionsTemplate, socketOptionsBase);
const userPage = index.user(
production, '/', 'style.css', 'bootstrap.js', 'bootstrap-es.js', socketOptions, false, !!args.local, !production);
const offlinePage = fs.readFileSync(pathTo('public', 'offline.html'), 'utf8');
+1 -1
View File
@@ -28,7 +28,6 @@ import { Move } from './move';
import { logger } from './logger';
import { findFriends } from './db';
import { Say, saySystem } from './chat';
import { getTile } from '../common/worldMap';
import { updateRegion, getExpectedRegion } from './regionUtils';
import { findEntities } from './serverMap';
import { FriendsService, toFriendOnline } from './services/friends';
@@ -37,6 +36,7 @@ import { swapCharacter } from './characterUtils';
import { isOutsideMap } from '../common/collision';
import { createAnEntity } from '../common/entities';
import { mockPaletteManager } from '../common/ponyInfo';
import { getTile } from '../common/tileUtils';
interface AddedEntity {
name: string;
+2 -2
View File
@@ -3,7 +3,6 @@ import * as fs from 'fs';
import { noop, random } from 'lodash';
import { HOUR, SECOND, SEASON, HOLIDAY, UNHIDE_TIMEOUT, MINUTE } from '../common/constants';
import { CharacterState, ServerConfig, Settings } from '../common/adminInterfaces';
import { ClientActions } from '../client/clientActions';
import {
updateAccountSafe, timeoutAccount, reportInviteLimitAccount, reportSwearingAccount, reportSpammingAccount,
reportFriendLimitAccount
@@ -31,6 +30,7 @@ import { updateCharacterState } from './characterUtils';
import { FriendsService } from './services/friends';
import { config } from './config';
import { parseSeason, parseHoliday } from '../common/utils';
import { ClientActionsTemplate } from '../common/clientActionsTemplte';
async function refreshSettings(account: IAccount) {
const a = await Account.findOne({ _id: account._id }, 'settings').exec();
@@ -105,7 +105,7 @@ export function createServerActionsFactory(
const move = createMove(teleportCounter);
const ignorePlayer = createIgnorePlayer(updateAccount);
async function createServerActions(client: ClientActions & SocketClient & ClientExtensions & IClient) {
async function createServerActions(client: ClientActionsTemplate & SocketClient & ClientExtensions & IClient) {
const { account } = client.tokenData as TokenData;
const [friendIds, hideIds] = await Promise.all([findFriendIds(account._id), findHideIds(account._id)]);
createClientAndPony(client, friendIds, hideIds, server, world, statesCounter);
+2 -2
View File
@@ -1,11 +1,11 @@
import { ClientExtensions, BinaryWriter } from 'ag-sockets';
import { ClientActions } from '../client/clientActions';
import {
Entity, ServerFlags, AccountSettings, NotificationFlags, Expression, Camera, SayData, Region, TileUpdate,
Rect, IMap, MapType, TileType, MapState, UpdateFlags, Action, EntityOrPonyOptions, EntityPlayerState, MapFlags
} from '../common/interfaces';
import { IAccount, ICharacter, UpdateAccount } from './db';
import { AccountUpdate, CharacterState, GameServerSettings, Suspicious } from '../common/adminInterfaces';
import { ClientActionsTemplate } from '../common/clientActionsTemplte';
export interface EntityUpdate {
entity: Entity;
@@ -132,7 +132,7 @@ export interface ServerMap extends IMap<ServerRegion> {
editingLocked: boolean;
}
export interface IClient extends ClientActions, ClientExtensions {
export interface IClient extends ClientActionsTemplate, ClientExtensions {
// origin info
ip: string;
country: string;
+2 -1
View File
@@ -3,7 +3,6 @@ import { fromByteArray } from 'base64-js';
import {
TileType, MapInfo, MapState, defaultMapState, Rect, MapType, ServerFlags, EntityFlags, MapFlags, EntityState
} from '../common/interfaces';
import { getRegionGlobal, getTile, getRegion } from '../common/worldMap';
import { distanceSquaredXY, containsPoint, hasFlag } from '../common/utils';
import { POSITION_MAX } from '../common/movementUtils';
import { getEntityTypeName, getEntityType, createAnEntity } from '../common/entities';
@@ -19,6 +18,8 @@ import { createCanvas } from './canvasUtilsNode';
import { mockPaletteManager } from '../common/ponyInfo';
import { setEntityName } from './entityUtils';
import { WallController } from './controllers/wallController';
import { getTile } from '../common/tileUtils';
import { getRegion, getRegionGlobal } from '../common/region';
export interface EntityData {
type: string;
+2 -2
View File
@@ -8,9 +8,9 @@ import {
} from '../common/constants';
import { rectToScreen } from '../common/positionUtils';
import { removeItem, hasFlag } from '../common/utils';
import { canCollideWith } from '../common/collision';
import { canCollideWith, setColliderDirty } from '../common/collision';
import { invalidateRegionsCollider, getRegionTile } from '../common/region';
import { setColliderDirty, setTilesDirty } from '../common/worldMap';
import { setTilesDirty } from '../common/tileUtils';
const subscribeBoundsBottomPad = 3;
+1 -1
View File
@@ -6,7 +6,7 @@ import { logger } from './logger';
import { SERVER_FPS } from '../common/constants';
import { ServerConfig } from '../common/adminInterfaces';
import { timingReset, timingStart, timingEnd } from './timing';
import { initializeTileHeightmaps } from '../client/tileUtils';
import { initializeTileHeightmaps } from '../common/tileUtils';
import { normalSpriteSheet } from '../generated/sprites';
import { pathTo } from './paths';
import { createMainMap } from './maps/mainMap';
+2 -3
View File
@@ -32,14 +32,13 @@ import { roundPosition, roundPositionXMidPixel, roundPositionYMidPixel } from '.
import { logger } from './logger';
import { updateCamera, centerCameraOn } from '../common/camera';
import { timingStart, timingEnd, timingUpdate } from './timing';
import { getRegionGlobal, getTile } from '../common/worldMap';
import { getEntityTypeName } from '../common/entities';
import { toFriendOnline, toFriendOffline, FriendsService } from './services/friends';
// import { Pool, createPool } from './pool';
import { isStaticCollision, fixCollision, updatePosition } from '../common/collision';
import { HidingService } from './services/hiding';
import { generateRegionCollider } from '../common/region';
import { updateTileIndices } from '../client/tileUtils';
import { generateRegionCollider, getRegionGlobal } from '../common/region';
import { getTile, updateTileIndices } from '../common/tileUtils';
import { removeEntityFromRegion } from './serverRegion';
import { createIslandMap } from './maps/islandMap';
import { createHouseMap } from './maps/houseMap';