diff --git a/src/ts/client/adminHtmlUtils.ts b/src/ts/client/adminHtmlUtils.ts new file mode 100644 index 0000000..829e4d1 --- /dev/null +++ b/src/ts/client/adminHtmlUtils.ts @@ -0,0 +1,141 @@ +import { LogEntry } from '../common/adminInterfaces'; +import { highlightWords, SupporterChange } from '../common/adminUtils'; +import { element, textNode } from './htmlUtils'; +import { faCaretSquareDown, faCaretSquareUp, faClock, faMinusCircle, faPlusCircle } from './icons'; +import { escape } from 'lodash'; + +export function createSupporterChanges(entries: LogEntry[]): SupporterChange[] { + const changes = entries.map(l => ({ + message: l.message, + level: +((/\d+/.exec(l.message) || ['0'])[0]), + added: /added/i.test(l.message), + date: new Date(l.date), + icon: /added/i.test(l.message) ? faPlusCircle : (/decline/i.test(l.message) ? faClock : faMinusCircle), + class: /added/i.test(l.message) ? 'text-success' : (/decline/i.test(l.message) ? 'text-warning' : 'text-danger'), + })); + + for (let i = 1; i < changes.length; i++) { + const prev = changes[i - 1]; + const current = changes[i]; + + if (current.date.getMonth() !== prev.date.getMonth()) { + current.class += ' border-left border-success pl-2'; + } + + if (current.added && prev.added) { + if (current.level > prev.level) { + current.icon = faCaretSquareUp; + current.class = 'text-info'; + } else if (current.level < prev.level) { + current.icon = faCaretSquareDown; + current.class = 'text-info'; + } + } + } + + return changes; +} + +function formatChatLine(l: string): HTMLElement { + // 00:00:01 [system] Timed out for swearing + // 00:00:01 [patreon] fetched patreon data + // 00:00:01 [dev][Autumn Leafs] hello world + // 00:00:01 [dev][Autumn Leafs][muted] hello world + // 00:00:01 [dev][Autumn Leafs][ignored] hello world + // 00:00:01 [dev-pl][Autumn Leafs][ignored] hello world + // 00:00:01 [57a3dc6f2f0019a161cdebf6][dev][Autumn Leafs][ignored] hello world + // 00:00:01 [1][dev][Autumn Leafs][ignored] hello world + // 00:00:01 [1:merged][dev][Autumn Leafs][ignored] hello world + // 00:00:01 [merged][dev][Autumn Leafs][ignored] hello world + // 00:00:01 [merged][dev][main][Autumn Leafs][ignored] hello world + + /* tslint:disable:max-line-length */ + const regex = /^([0-9:]+) (\[(?:merged|\d+|\d+:merged|[a-z0-9]{24})\])?\[([a-z0-9_-]+)\](?:\[([a-z0-9_-]+)\])?((?:\[.*?\])?)(?:\[(muted|ignored|ignorepub)\])?\t(.*)$/; + const m = regex.exec(l); + + if (m) { + const [, time, accountId, server, map, name, mutedIgnored, message] = m; + const messageTag = server === 'system' ? 'system' : getMessageTag(message); + const modTag = mutedIgnored ? ' message-muted' : ''; + + return element('div', 'chatlog-line', [ + element('span', 'time', [], { 'data-text': time }), + accountId ? element('span', 'account-id', [textNode(accountId)]) : undefined, + element('span', `server server-${server.replace(/-.+$/g, '')}`, [textNode(`[${server}]`)]), + map ? element('span', `map map-${map}`, [textNode(`[${map}]`)]) : undefined, + element('span', mutedIgnored ? `name ${mutedIgnored}` : `name`, [textNode(name)]), + textNode(' '), + element('span', `message message-${messageTag}${modTag}`, [textNode(message)]), + textNode(' '), + element('a', 'chat-translate', [], undefined, { click: translateChat }), + ]); + } else { + return element('div', '', [textNode(highlightWords(l))]); + } +} + +function translateChat(this: HTMLElement) { + const lines: string[] = []; + let parent = this.parentElement; + + for (let i = 0; parent && i < 10; i++) { + lines.push(parent.querySelector('.message')!.textContent!); + parent = parent.nextElementSibling as HTMLElement; + } + + window.open(`https://translate.google.com/#auto/en/${encodeURIComponent(lines.join('\n'))}`); +} + +if (typeof window !== 'undefined') { + (window as any).goToAccount = (accountId: string) => { + window.dispatchEvent(new CustomEvent('go-to-account', { detail: accountId })); + }; +} + +export function formatChat(chat: string): HTMLElement[] { + return (chat || '') + .trim() + .split(/\r?\n/g) + .reverse() + .map(formatChatLine); +} + + +function getMessageTag(message: string) { + if (/^\/p /.test(message)) { + return 'party'; + } else if (/^\/w /.test(message)) { + return 'whisper'; + } else if (/^\/s[s123] /.test(message)) { + return 'supporter'; + } else if (/^\//.test(message)) { + return 'command'; + } else { + return 'none'; + } +} + +export function replaceSwears(element: HTMLElement) { + const text = element.textContent; + + if (text) { + const replaced = encWithHighlight(text); + + if (text !== replaced) { + element.innerHTML = replaced; + } + } +} + +function enc(text?: string): string { + return escape(text || ''); +} + +function encWithHighlight(text?: string): string { + return highlightWords(enc(text || '')); +} + +export function formatEventDesc(text: string): string { + return encWithHighlight(text).replace(/\[([a-z0-f]{24})\]/g, `[$1]`); +} + diff --git a/src/ts/client/buttonActions.ts b/src/ts/client/buttonActions.ts index 61c732b..fb14c03 100644 --- a/src/ts/client/buttonActions.ts +++ b/src/ts/client/buttonActions.ts @@ -11,27 +11,27 @@ import { PonyTownGame } from './game'; import { boopAction, upAction, downAction, turnHeadAction } from './playerActions'; import { ACTIONS_LIMIT, COMMAND_ACTION_TIME_DELAY } from '../common/constants'; import { cloneDeep, hasFlag } from '../common/utils'; -import { boop, defaultHeadFrame, stand, sneeze, yawn, lie, sit, fly, laugh, kiss, excite } from './ponyAnimations'; +import { boop, defaultHeadFrame, stand, sneeze, yawn, lie, sit, fly, laugh, kiss, excite } from '../common/ponyAnimations'; import { createDefaultPony, syncLockedPonyInfo, toPalette, mockPaletteManager } from '../common/ponyInfo'; import { ACTION_EXPRESSION_EYE_COLOR, ACTION_EXPRESSION_BG, ACTION_ACTION_COAT_COLOR, WHITE, HEARTS_COLOR, ACTION_COMMAND_BG, BLACK, ACTION_ACTION_BG, ACTION_ITEM_BG, blushColor, ENTITY_ITEM_BG, TRANSPARENT } from '../common/colors'; -import { resizeCanvasWithRatio, getPixelRatio, disableImageSmoothing } from './canvasUtils'; +import { resizeCanvasWithRatio, getPixelRatio, disableImageSmoothing } from '../common/canvasUtils'; import { drawCanvas, ContextSpriteBatch } from '../graphics/contextSpriteBatch'; -import { defaultPonyState, defaultDrawPonyOptions } from './ponyHelpers'; +import { defaultPonyState, defaultDrawPonyOptions } from '../common/ponyHelpers'; import { drawHead, drawPony } from './ponyDraw'; import { parseColor, toGrayscale, colorToHexRGB } from '../common/color'; import { rect, addRects, centerPoint } from '../common/rect'; import { drawTextAligned, HAlign, VAlign } from '../graphics/spriteFont'; -import { fontPal } from '../client/fonts'; +import { fontPal } from '../common/fonts'; import { isPonyLying, isPonySitting, isPonyStanding, isPonyFlying } from '../common/entityUtils'; -import { canPonyFly } from '../common/pony'; +import { canPonyFly } from './pony'; import { apple2, createAnEntity } from '../common/entities'; import { fakePaletteManager } from '../common/mixins'; -import { spriteSheetsLoaded } from './spriteUtils'; import { getEntityTypesFromName } from '../components/services/model'; import { toWorldY, toWorldX } from '../common/positionUtils'; +import { spriteSheetsLoaded } from './loadSprites'; const CANVAS_SIZE = 29; const ICON_SIZE = 16; diff --git a/src/ts/client/clientActions.ts b/src/ts/client/clientActions.ts index 4568caf..4117f60 100644 --- a/src/ts/client/clientActions.ts +++ b/src/ts/client/clientActions.ts @@ -1,12 +1,11 @@ import { NgZone } from '@angular/core'; -import { Method, SocketClient, Bin, getMethods } from 'ag-sockets/dist/browser'; +import { getMethods } from 'ag-sockets/dist/browser'; import { MapInfo, WorldState, PartyMember, PartyFlags, Action, NotificationFlags, Pony, LeaveReason, SayData, MapState, defaultMapState, Apply, InfoFlags, PonyData, FriendStatusData, WorldMap } from '../common/interfaces'; import { hasFlag, findById } from '../common/utils'; -import { isPony } from '../common/pony'; -import { setTileAtRegion, findEntityById, createWorldMap, removeRegions, updateMapState } from '../common/worldMap'; +import { setTileAtRegion, findEntityById, createWorldMap, removeRegions, updateMapState } from './worldMap'; import { GameService } from '../components/services/gameService'; import { PonyTownGame } from './game'; import { supportsLetAndConst, isInIncognitoMode } from './clientUtils'; @@ -19,20 +18,18 @@ import { updatePonyInfoWithPoof, subscribeRegion, handleUpdates, handleUpdateEntity, handleRemoveEntity, handleSays, handleEntityInfo, handleUpdatePonies, filterEntityName, handleUpdateFriends } from './handlers'; -import { nameToHTML } from './emoji'; - -const BinEntityId = Bin.U32; -const BinEntityPlayerState = Bin.U8; -const BinNotificationId = Bin.U16; -const BinSayDatas = [BinEntityId, Bin.Str, Bin.U8]; +import { nameToHTML } from '../common/emoji'; +import { ClientActionsTemplate } from '../common/clientActionsTemplte'; +import { isPony } from '../common/entityUtils'; function findPonyById(map: WorldMap, id: number) { const entity = findEntityById(map, id); return entity && isPony(entity) ? entity : undefined; } -export class ClientActions implements SocketClient { +export class ClientActions extends ClientActionsTemplate { constructor(private gameService: GameService, private game: PonyTownGame, private model: Model, private zone: NgZone) { + super(); } private apply: Apply = func => this.zone.run(func); connected() { @@ -57,29 +54,29 @@ export class ClientActions implements SocketClient { invalidVersion() { DEVELOPMENT && !TESTS && console.error('Invalid version'); } - @Method({ binary: [Bin.U32] }) + // @Method({ binary: [Bin.U32] }) queue(place: number) { this.game.placeInQueue = place; } - @Method({ binary: [Bin.Obj, Bin.Bool] }) + // @Method({ binary: [Bin.Obj, Bin.Bool] }) worldState(state: WorldState, initial: boolean) { this.game.placeInQueue = 0; this.game.setWorldState(state, initial); } - @Method({ binary: [Bin.Obj, Bin.Obj] }) + // @Method({ binary: [Bin.Obj, Bin.Obj] }) mapState(info: MapInfo, state: MapState) { this.game.map = createWorldMap(info, state); this.game.player = undefined; this.game.setupMap(); updateMapState(this.game.map, defaultMapState, this.game.map.state); } - @Method({ binary: [Bin.Obj] }) + // @Method({ binary: [Bin.Obj] }) mapUpdate(state: MapState) { const prevState = this.game.map.state; this.game.map.state = state; updateMapState(this.game.map, prevState, this.game.map.state); } - @Method({ binary: [] }) + // @Method({ binary: [] }) mapSwitching() { this.game.loaded = false; this.game.placeInQueue = 0; @@ -89,13 +86,13 @@ export class ClientActions implements SocketClient { this.game.player.vy = 0; } } - @Method({ binary: [Bin.I32, Bin.I32, Bin.U8Array] }) + // @Method({ binary: [Bin.I32, Bin.I32, Bin.U8Array] }) mapTest(width: number, height: number, buffer: Uint8Array) { const data = new Uint32Array(width * height); (new Uint8Array(data.buffer)).set(buffer); this.game.minimap = { width, height, data }; } - @Method({ binary: [BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U16] }) + // @Method({ binary: [BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U16] }) myEntity(id: number, name: string, info: string, characterId: string, crc: number) { this.game.playerId = id; this.game.playerName = name; @@ -122,7 +119,7 @@ export class ClientActions implements SocketClient { this.game.onActionsUpdate.next(); } - @Method({ binary: [[Bin.U8], [Bin.U8Array], Bin.U8Array, [Bin.U8Array], BinSayDatas] }) + // @Method({ binary: [[Bin.U8], [Bin.U8Array], Bin.U8Array, [Bin.U8Array], BinSayDatas] }) update(unsubscribes: number[], subscribes: Uint8Array[], updates: Uint8Array | null, regions: Uint8Array[], says: SayData[]) { removeRegions(this.game.map, unsubscribes); @@ -158,7 +155,7 @@ export class ClientActions implements SocketClient { handleSays(this.game, id, message, type); } } - @Method({ binary: [Bin.F32, Bin.F32, Bin.Bool] }) + // @Method({ binary: [Bin.F32, Bin.F32, Bin.Bool] }) fixPosition(x: number, y: number, safe: boolean) { if (DEVELOPMENT && !TESTS && !safe) { console.error(`fix position (${x.toFixed(2)}, ${y.toFixed(2)})`); @@ -174,7 +171,7 @@ export class ClientActions implements SocketClient { this.game.send(server => server.fixedPosition()); } - @Method({ binary: [BinEntityId, Bin.U8, Bin.Obj] }) + // @Method({ binary: [BinEntityId, Bin.U8, Bin.Obj] }) actionParam(id: number, action: Action, param: any) { switch (action) { case Action.ACL: @@ -189,13 +186,13 @@ export class ClientActions implements SocketClient { DEVELOPMENT && !TESTS && console.error(`actionParam: Invalid action: ${action}`); } } - @Method({ binary: [Bin.U8] }) + // @Method({ binary: [Bin.U8] }) left(reason: LeaveReason) { this.game.player = undefined; this.game.map = createWorldMap(); this.apply(() => this.gameService.left('clientActions.left', reason)); } - @Method({ binary: [BinNotificationId, BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U8] }) + // @Method({ binary: [BinNotificationId, BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U8] }) addNotification(id: number, entityId: number, name: string, message: string, note: string, flags: NotificationFlags) { const defaultCharacter = hasFlag(flags, NotificationFlags.Supporter) ? this.game.supporterPony : this.game.offlinePony; const pony = (entityId && findPonyById(this.game.map, entityId)) || defaultCharacter; @@ -205,17 +202,17 @@ export class ClientActions implements SocketClient { this.apply(() => addNotification(this.game, { id, message, note, pony, flags, open: false, fresh: true })); } - @Method({ binary: [BinNotificationId] }) + // @Method({ binary: [BinNotificationId] }) removeNotification(id: number) { this.apply(() => removeNotification(this.game, id)); } - @Method({ binary: [BinEntityId, BinEntityId] }) + // @Method({ binary: [BinEntityId, BinEntityId] }) updateSelection(currentId: number, newId: number) { if (isSelected(this.game, currentId)) { this.game.select(newId ? findPonyById(this.game.map, newId) : undefined); } } - @Method({ binary: [[BinEntityId, Bin.U8]] }) + // @Method({ binary: [[BinEntityId, Bin.U8]] }) updateParty(party: [number, PartyFlags][] | undefined) { const members = party && party.map(([id, flags]) => ({ id, @@ -239,26 +236,26 @@ export class ClientActions implements SocketClient { this.game.onPartyUpdate.next(); }); } - @Method({ binary: [[BinEntityId, Bin.Obj, Bin.U8Array, Bin.U8Array, BinEntityPlayerState, Bin.Bool]] }) + // @Method({ binary: [[BinEntityId, Bin.Obj, Bin.U8Array, Bin.U8Array, BinEntityPlayerState, Bin.Bool]] }) updatePonies(ponies: PonyData[]) { handleUpdatePonies(this.game, ponies); } - @Method({ binary: [Bin.Obj, Bin.Bool] }) + // @Method({ binary: [Bin.Obj, Bin.Bool] }) updateFriends(friends: FriendStatusData[], removeMissing: boolean) { handleUpdateFriends(this.game, friends, removeMissing); } - @Method({ binary: [BinEntityId, Bin.Str, Bin.U32, Bin.Bool] }) + // @Method({ binary: [BinEntityId, Bin.Str, Bin.U32, Bin.Bool] }) entityInfo(id: number, name: string, crc: number, nameBad: boolean) { handleEntityInfo(this.game, id, name, crc, nameBad); } - @Method({ binary: [Bin.Obj] }) + // @Method({ binary: [Bin.Obj] }) entityList(value: { name: string; x: number; y: number; }[]) { if (DEVELOPMENT || BETA) { const list = value.map(({ name, x, y }) => `${name}(${x.toFixed(2)}, ${y.toFixed(2)})`).join('\n'); console.log(`ENTITIES:\n${list}`); } } - @Method({ binary: [Bin.Obj] }) + // @Method({ binary: [Bin.Obj] }) testPositions(data: { frame: number; x: number | undefined; y: number | undefined; moved: boolean; }[]) { if (DEVELOPMENT) { const round = (x: number) => Math.round(x * 100); diff --git a/src/ts/client/clientAdminActions.ts b/src/ts/client/clientAdminActions.ts index ada1ea8..56cde28 100644 --- a/src/ts/client/clientAdminActions.ts +++ b/src/ts/client/clientAdminActions.ts @@ -1,16 +1,10 @@ -import { Method } from 'ag-sockets/dist/browser'; import { AdminModel } from '../components/services/adminModel'; -import { ModelTypes } from '../common/adminInterfaces'; import { ModelSubscriber } from '../components/services/modelSubscriber'; +import { ClientAdminActionsTemplate, ClientUpdate } from '../common/clientAdminActionsTemplate'; -export interface ClientUpdate { - type: ModelTypes; - id: string; - update: any; -} - -export class ClientAdminActions { +export class ClientAdminActions extends ClientAdminActionsTemplate { constructor(private model: AdminModel) { + super(); } connected() { this.model.initialize(true); @@ -19,7 +13,7 @@ export class ClientAdminActions { disconnected() { this.model.updateTitle(); } - @Method() + //@Method() updates(updates: ClientUpdate[]) { for (const { type, id, update } of updates) { const model = this.model[type] as ModelSubscriber; diff --git a/src/ts/client/clientUtils.ts b/src/ts/client/clientUtils.ts index db64d99..0cfd877 100644 --- a/src/ts/client/clientUtils.ts +++ b/src/ts/client/clientUtils.ts @@ -4,10 +4,10 @@ import { AccountData, AccountDataFlags } from '../common/interfaces'; import { - PLAYER_NAME_MAX_LENGTH, SAY_MAX_LENGTH, SAYS_TIME_MIN, SAYS_TIME_MAX, isChatlogRangeUnlimited, SUPPORTER_REWARDS, + SAY_MAX_LENGTH, SAYS_TIME_MIN, SAYS_TIME_MAX, isChatlogRangeUnlimited, SUPPORTER_REWARDS, PAST_SUPPORTER_REWARDS } from '../common/constants'; -import { matcher, isSurrogate, fromSurrogate, isLowSurrogate } from '../common/stringUtils'; +import { matcher } from '../common/stringUtils'; import { oauthProviders } from './data'; import { Subject } from '../../../node_modules/rxjs'; import { PonyTownGame } from './game'; @@ -16,147 +16,6 @@ import { hasFlag } from '../common/utils'; export const matchCyrillic = /[\u0400-\u04FF]/g; export const containsCyrillic = matcher(matchCyrillic); - -const otherValid = [ - '♂♀⚲⚥⚧☿♁⚨⚩⚦⚢⚣⚤', // gender symbols - '™®♥♦♣♠❥♡♢♤♧ღஐ·´°•◦✿❀◆◇◈◉◊。¥€«»,:■□—', // other - '〈〉「」『』【】《》♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼№●○◌★☆✰✦✧▪▫・', // other 2 - '\u1160\u3000\u3164', // spaces (replaced later) -].join('').split('').reduce((set, c) => (set.add(c.charCodeAt(0)), set), new Set()); - -export function isValid(c: number): boolean { - return (c >= 0x0020 && c <= 0x007e) // latin - || (c >= 0x00a0 && c <= 0x00ff) // latin 1 supplement - || (c >= 0x0100 && c <= 0x017F) // Latin Extended-A - || (c >= 0x0180 && c <= 0x024F) // Latin Extended-B - || (c >= 0x1e00 && c <= 0x1eff) // Latin Extended Additional - || (c >= 0x0370 && c <= 0x03FF) // Greek and Coptic - || (c >= 0x0400 && c <= 0x0481) || (c >= 0x048A && c <= 0x04FF) // cyrillic - || (c >= 0x3041 && c <= 0x3096) // hiragana - || (c >= 0x30A0 && c <= 0x30FF) // hatakana - || (c >= 0x3400 && c <= 0x4DB5) || (c >= 0x4E00 && c <= 0x9FCB) || (c >= 0xF900 && c <= 0xFA6A) // kanji - || (c >= 0x2F00 && c <= 0x2FDF) // Kangxi Radicals - || (c >= 0x3000 && c <= 0x302D) // CJK Symbols and Punctuation - || (c >= 0x1D00 && c <= 0x1D7F) // Phonetic Extensions - || (c >= 0x0250 && c <= 0x02AF) // IPA Extensions - || (c >= 0xA720 && c <= 0xA7FF) // Latin Extended-D - || (c >= 0x0E00 && c <= 0x0E7F) // Thai - || (c >= 0xff01 && c <= 0xff5e) // Romaji (replaced later) - || (c >= 0x2200 && c <= 0x22FF) // Mathematical Operators - || (c >= 0x25A0 && c <= 0x25FF) // Geometric Shapes - || (c >= 0x2600 && c <= 0x26ff) || (c >= 0x2700 && c <= 0x27bf) || (c >= 0x2b00 && c <= 0x2bef) // emoji - || (c >= 0x1f600 && c <= 0x1f64f) || (c >= 0x1f680 && c <= 0x1f6f6) || (c >= 0x1f300 && c <= 0x1f5ff) // emoji - || (c >= 0x231a && c <= 0x231b) || (c >= 0x23e9 && c <= 0x23fa) // emoji - || (c >= 0x1f900 && c <= 0x1f9ff) // Supplemental Symbols and Pictographs - || otherValid.has(c) // other symbols - ; -} - -export function isValid2(c: number): boolean { - return (c >= 0x2b0 && c <= 0x2ff) // Spacing Modifier Letters - || (c >= 0x531 && c <= 0x556) || (c >= 0x559 && c <= 0x55f) || (c >= 0x561 && c <= 0x587) - || (c >= 0x589 && c <= 0x58a) || (c >= 0x58c && c <= 0x58f) // Armenian - || (c >= 0x591 && c <= 0x5c7) || (c >= 0x5d0 && c <= 0x5ea) || (c >= 0x5f0 && c <= 0x5f4) // Hebrew - || (c >= 0x600 && c <= 0x6ff) // Arabic - || (c >= 0x7c0 && c <= 0x7fa) // NKo - || (c >= 0x900 && c <= 0x97f) // Devanagari - || (c === 0xb90) || (c === 0xb9c) // Tamil - || (c >= 0xc85 && c <= 0xc8c) || (c >= 0xc8e && c <= 0xc90) || (c >= 0xc91 && c <= 0xca8) - || (c >= 0xcaa && c <= 0xcb3) || (c >= 0xcb5 && c <= 0xcb9) || (c >= 0xce6 && c <= 0xcef) // Kannada - || (c >= 0x10a0 && c <= 0x10c5) || (c === 0x10c7) || (c === 0x10cd) || (c >= 0x10d0 && c <= 0x10ff) // Georgian - || (c >= 0x1100 && c <= 0x11ff) || (c >= 0x3130 && c <= 0x318f) || (c >= 0xac00 && c <= 0xd7af) // Hangul - || (c >= 0x1400 && c <= 0x167f) // Unified Canadian Aboriginal Syllabics - || (c >= 0x2010 && c <= 0x2027) || (c >= 0x2030 && c <= 0x205e) // General Punctuation - || (c >= 0x20a0 && c <= 0x20bf) // Currency Symbols - || (c >= 0x2100 && c <= 0x214f) // Letterlike Symbols - || (c >= 0x2150 && c <= 0x218b) // Number Forms - || (c >= 0x2300 && c <= 0x239a) || (c >= 0x23b4 && c <= 0x23fa) // Miscellaneous Technical - || (c >= 0x2500 && c <= 0x257f) // Box Drawing - || (c >= 0x2800 && c <= 0x28ff) // Braille Patterns - || (c >= 0x3000 && c <= 0x303f) // CJK Symbols and Punctuation - || (c >= 0x3105 && c <= 0x312d) // Bopomofo - || (c >= 0xfe30 && c <= 0xfe4f) // CJK Compatibility Forms - || (c >= 0xff01 && c <= 0xffef) // Halfwidth and Fullwidth Forms - // || (c >= 0x1f170 && c < 0x1f189) // Enclosed Alphanumeric Supplement [a-z] - || (c >= 0x1f000 && c <= 0x1f02b) // Mahjong Tiles - || (c >= 0x1f0a0 && c <= 0x1f0ae) || (c >= 0x1f0b1 && c <= 0x1f0bf) || (c >= 0x1f0c1 && c <= 0x1f0cf) - || (c >= 0x1f0d1 && c <= 0x1f0df) || (c >= 0x1f0e0 && c <= 0x1f0f5) // Playing Cards - || (c >= 0x1f1e6 && c <= 0x1f1ff) // Enclosed Alphanumeric Supplement (regional indicators) - ; -} - -function isInvalid(c: number): boolean { - return c === 0x1f595 // middle finger emoji - || c === 0x00ad // soft hyphen - ; -} - -function isValidForName(c: number): boolean { - return isValid(c) && !isInvalid(c); -} - -function isValidForMessage(c: number): boolean { - return (isValid(c) || isValid2(c)) && !isInvalid(c); -} - -export const matchRomaji = /[\uff01-\uff5e]/g; - -const matchOtherWhitespace = /[\u1160\u2800\u3000\u3164\uffa0]+/g; - -export function replaceRomaji(match: string): string { - return String.fromCharCode(match.charCodeAt(0) - 0xfee0); -} - -export function cleanName(name: string | undefined): string { - return filterString(name, isValidForName) - .replace(matchOtherWhitespace, ' ') // whitespace characters - .replace(/\s+/g, ' ') - .replace(matchRomaji, replaceRomaji) - .trim(); -} - -export function cleanMessage(text: string | undefined): string { - return filterString(text, isValidForMessage) - .replace(matchOtherWhitespace, ' ') // whitespace characters - .replace(/[\r\n]/g, '') - .replace(matchRomaji, replaceRomaji) - .trim() - .substr(0, SAY_MAX_LENGTH); -} - -export function filterString(value: string | undefined, filter: (code: number) => boolean): string { - value = value || ''; - - for (let i = 0; i < value.length; i++) { - let code = value.charCodeAt(i); - let size = 1; - let invalidSurrogate = false; - - if (isSurrogate(code) && (i + 1) < value.length) { - const extra = value.charCodeAt(i + 1); - - if (isLowSurrogate(extra)) { - code = fromSurrogate(code, extra); - i++; - size++; - } else { - invalidSurrogate = true; - } - } - - if (invalidSurrogate || !filter(code)) { - i -= size; - value = value.substr(0, i + 1) + value.substr(i + size + 1); - } - } - - return value; -} - -export function validatePonyName(name: string | undefined): boolean { - return !!name && !!name.length && name.length <= PLAYER_NAME_MAX_LENGTH && !/^[.,_-]+$/.test(name); -} - export function toSocialSiteInfo({ id, name, url, provider }: SocialSite): SocialSiteInfo { const oauth = oauthProviders.find(p => p.id === provider); diff --git a/src/ts/client/draw.ts b/src/ts/client/draw.ts index 89bb8fe..ebb8748 100644 --- a/src/ts/client/draw.ts +++ b/src/ts/client/draw.ts @@ -6,12 +6,13 @@ import { drawBounds, drawPixelText, drawBoundsOutline, drawOutlineRect, drawWorl import { ORANGE, BLUE, PURPLE, BLACK, RED, WHITE, CYAN, HOTPINK, GRAY } from '../common/colors'; import { toScreenX, toScreenY, toWorldX, toWorldY } from '../common/positionUtils'; import { tileWidth, tileHeight, PONY_TYPE, REGION_SIZE, REGION_WIDTH, REGION_HEIGHT } from '../common/constants'; -import { forEachRegion, getAnyBounds, getRegion, isInWaterAt } from '../common/worldMap'; -import { drawPonyEntity, drawPonyEntityLight, drawPonyEntityLightSprite } from '../common/pony'; +import { forEachRegion, getAnyBounds } from './worldMap'; +import { drawPonyEntity, drawPonyEntityLight, drawPonyEntityLightSprite } from './pony'; import { getInteractBounds, sortEntities, isHidden, getSitOnBounds } from '../common/entityUtils'; -import { drawTiles, drawTilesNew, drawTilesDebugInfo } from './tileUtils'; +import { drawTiles, drawTilesNew, drawTilesDebugInfo, isInWaterAt } from '../common/tileUtils'; import { withAlphaFloat } from '../common/color'; -import { timeStart, timeEnd } from './timing'; +import { timeStart, timeEnd } from '../common/timing'; +import { getRegion } from '../common/region'; const SELECTED_ENTITY_BOUNDS = withAlphaFloat(ORANGE, 0.5); diff --git a/src/ts/client/game.ts b/src/ts/client/game.ts index 306c31a..2bdc377 100644 --- a/src/ts/client/game.ts +++ b/src/ts/client/game.ts @@ -17,26 +17,25 @@ import { } from '../common/constants'; import { ensureAllVisiblePoniesAreDecoded, invalidatePalettes, updateMap, updateEntities, - getMapHeightAt, updateEntitiesWithNames, updateEntitiesCoverLifted, getTile, + getMapHeightAt, updateEntitiesWithNames, updateEntitiesCoverLifted, pickEntities, updateEntitiesTriggers, getElevation, setElevation, createWorldMap -} from '../common/worldMap'; +} from './worldMap'; import { updateCamera, centerCameraOn, screenToWorld, createCamera } from '../common/camera'; import { WHITE, BLACK, SHADOW_COLOR, getTileColor, RED, CAVE_LIGHT, CAVE_SHADOW } from '../common/colors'; import { formatHourMinutes, getLightColor, getShadowColor, createLightData } from '../common/timeUtils'; import { toggleWalls } from '../common/mixins'; import { getEntityTypeName, hammer, broom, createAnEntity, saw, placeableEntities, shovel } from '../common/entities'; -import { hasExtendedInfo, setHeadAnimation, createPony } from '../common/pony'; +import { hasExtendedInfo, setHeadAnimation, createPony } from './pony'; import { PaletteManager } from '../graphics/paletteManager'; import { isWebGL2 } from '../graphics/webgl/webglUtils'; import { drawFullScreenMessage, drawNames, drawChat } from '../graphics/graphicsUtils'; import { Key } from './input/input'; -import { loadAndInitSpriteSheets } from './spriteUtils'; import { version, isMobile } from './data'; import { Game } from './gameLoop'; import { Audio } from '../components/services/audio'; -import { getPixelRatio } from './canvasUtils'; +import { getPixelRatio } from '../common/canvasUtils'; import { colorToFloatArray, parseColor, colorToExistingFloatArray, makeTransparent } from '../common/color'; -import { nom } from './ponyAnimations'; +import { nom } from '../common/ponyAnimations'; import { InputManager } from './input/inputManager'; import { roundPositionX, roundPositionY, toScreenX, toScreenY } from '../common/positionUtils'; import { StorageService } from '../components/services/storageService'; @@ -51,17 +50,17 @@ import { ClientSocketService } from '../components/services/gameService'; import { attachDebugMethod, initFeatureFlags, updateRangeIndicator, initLogger, log, getSaysTime } from './clientUtils'; import { restorePlayerPosition, savePlayerPosition } from './sec'; import { drawEntityLights, drawEntityLightSprites, drawMap, drawDebugRegions } from './draw'; -import { updateTileSets, initializeTileHeightmaps } from './tileUtils'; +import { updateTileSets, initializeTileHeightmaps, getTile } from '../common/tileUtils'; import { downAction, upAction, turnHeadAction, boopAction, interact, toggleWall, editorMoveEntities, editorSelectEntities, editorDragEntities } from './playerActions'; -import { fontSmallPal, fontSmall, font, fontMono } from './fonts'; +import { fontSmallPal, fontSmall, font, fontMono } from '../common/fonts'; import { drawText, drawOutlinedText, measureText } from '../graphics/spriteFont'; import { initializeToys } from './ponyDraw'; import { ErrorReporter } from '../components/services/errorReporter'; import { mockPaletteManager } from '../common/ponyInfo'; -import { timeStart, timeEnd, timingCollate, timeReset } from './timing'; +import { timeStart, timeEnd, timingCollate, timeReset } from '../common/timing'; import { createFrameBuffer, bindFrameBuffer, unbindFrameBuffer, disposeFrameBuffer } from '../graphics/webgl/frameBuffer'; import { WebGL, initWebGL, disposeWebGL, initWebGLResources } from './webgl'; import { bindTexture } from '../graphics/webgl/texture2d'; @@ -72,6 +71,7 @@ import { createMat4, ortho } from '../common/mat4'; import { Model } from '../components/services/model'; import { filterEntityName } from './handlers'; import { isOutsideMap } from '../common/collision'; +import { loadAndInitSpriteSheets } from './loadSprites'; interface Minimap { width: number; diff --git a/src/ts/client/handlers.ts b/src/ts/client/handlers.ts index 7174242..2a03c06 100644 --- a/src/ts/client/handlers.ts +++ b/src/ts/client/handlers.ts @@ -8,15 +8,15 @@ import { } from '../common/interfaces'; import { bitmask, setFlag, findById, distance, hasFlag, distanceXY, invalidEnum, removeItem } from '../common/utils'; import { isChatVisible } from '../common/camera'; -import { createRegion, worldToRegionX, worldToRegionY } from '../common/region'; +import { createRegion, getRegionGlobal, getRegionUnsafe, worldToRegionX, worldToRegionY } from '../common/region'; import { createAnEntity, poof, poof2 } from '../common/entities'; -import { getPonyState, setPonyState, isPonyFlying, addChatBubble, isHidden } from '../common/entityUtils'; +import { getPonyState, setPonyState, isPonyFlying, addChatBubble, isHidden, addOrRemoveFromEntityList, isPony } from '../common/entityUtils'; import { - isPony, createPony, setPonyExpression, updatePonyInfo, updatePonyHold, doPonyAction, hasHeadAnimation, + createPony, setPonyExpression, updatePonyInfo, updatePonyHold, doPonyAction, hasHeadAnimation, setHeadAnimation, doBoopPonyAction, isPonyBug -} from '../common/pony'; +} from './pony'; import { PonyTownGame } from './game'; import { setupPlayer, savePlayerPosition } from './sec'; import { PONY_INFO_KEY, FLY_DELAY, isChatlogRangeUnlimited, SECOND, PONY_TYPE } from '../common/constants'; @@ -26,15 +26,16 @@ import { decodeUpdate, readOneUpdate } from '../common/encoders/updateDecoder'; import { updateEntityVelocity } from '../common/entityUtils'; import { decodePonyInfo } from '../common/compressPony'; import { mockPaletteManager } from '../common/ponyInfo'; -import { yawn, laugh, sneeze, kiss, kissFly, kissFlyBug, excite } from './ponyAnimations'; +import { yawn, laugh, sneeze, kiss, kissFly, kissFlyBug, excite } from '../common/ponyAnimations'; import { - findEntityById, getRegionGlobal, setTile, removeEntity, addEntity, removeEntityDirectly, setRegion, - addEntityToMapRegion, switchEntityRegion, getRegionUnsafe, addOrRemoveFromEntityList, -} from '../common/worldMap'; + findEntityById, removeEntity, addEntity, removeEntityDirectly, setRegion, + addEntityToMapRegion, switchEntityRegion, +} from './worldMap'; import { isSelected } from './gameUtils'; import { compareFriends } from '../components/services/model'; import { canCollideWith } from '../common/collision'; import { hasDrawLight, hasLightSprite } from './draw'; +import { setTile } from '../common/tileUtils'; function log(message: string) { if (DEVELOPMENT && !TESTS) { diff --git a/src/ts/client/htmlUtils.ts b/src/ts/client/htmlUtils.ts index fe9ff58..96845aa 100644 --- a/src/ts/client/htmlUtils.ts +++ b/src/ts/client/htmlUtils.ts @@ -1,6 +1,6 @@ -import { hasEmojis, splitEmojis, findEmoji, getEmojiImageAsync } from './emoji'; +import { hasEmojis, splitEmojis, findEmoji, getEmojiImageAsync } from '../common/emoji'; import { Dict } from '../common/interfaces'; -import { font } from './fonts'; +import { font } from '../common/fonts'; import { getCharacterSprite } from '../graphics/spriteFont'; export function createHtmlNodes(value: string | undefined, scale: number): Node[] { diff --git a/src/ts/client/spriteUtils.ts b/src/ts/client/loadSprites.ts similarity index 54% rename from src/ts/client/spriteUtils.ts rename to src/ts/client/loadSprites.ts index 57c1d9c..3bf9d1c 100644 --- a/src/ts/client/spriteUtils.ts +++ b/src/ts/client/loadSprites.ts @@ -1,31 +1,9 @@ -import { once, noop } from 'lodash'; -import { ColorExtra, ColorExtraSets, PonyEye, SpriteSheet, Sprite } from '../common/interfaces'; -import { spriteSheets } from '../generated/sprites'; -import { loadImage, createCanvas } from '../client/canvasUtils'; -import { getUrl } from './rev'; -import { createFonts } from './fonts'; - -export function createSprite(x: number, y: number, w: number, h: number, ox: number, oy: number, type: number): Sprite { - return { x, y, w, h, ox, oy, type }; -} - -export function addTitles(sprites: ColorExtraSets, titles: string[]): ColorExtraSets { - return sprites && sprites.map((ns, i) => - ns && ns.map(s => s && { color: s.color, colors: s.colors, title: titles[i], label: titles[i] })); -} - -export function addLabels(sprites: ColorExtraSets, labels: string[]) { - sprites && sprites.forEach((s, i) => s && s[0] ? s[0]!.label = labels[i] : undefined); - return sprites; -} - -export function createEyeSprite(eye: PonyEye | undefined, iris: number, defaultPalette: Uint32Array): ColorExtra | undefined { - return eye && { color: eye.irises[iris]!, colors: 2, extra: eye.base, palettes: [defaultPalette] }; -} - -export function getColorCount(sprite: ColorExtra | undefined): number { - return sprite && sprite.colors ? Math.floor((sprite.colors - 1) / 2) : 0; -} +import { noop, once } from "lodash"; +import { getUrl } from "./rev"; +import { spriteSheets } from "../generated/sprites"; +import { createCanvas, loadImage } from "../common/canvasUtils"; +import { createFonts } from "../common/fonts"; +import { SpriteSheet } from "../common/interfaces"; export function createSpriteUtils() { createFonts(); diff --git a/src/ts/client/playerActions.ts b/src/ts/client/playerActions.ts index f5c4f60..f29bbc7 100644 --- a/src/ts/client/playerActions.ts +++ b/src/ts/client/playerActions.ts @@ -1,5 +1,5 @@ import { isCommand, processCommand, hasFlag, includes, point } from '../common/utils'; -import { canPonyLie, canPonyFlyUp, canPonyStand, canPonySit, doBoopPonyAction } from '../common/pony'; +import { canPonyLie, canPonyFlyUp, canPonyStand, canPonySit, doBoopPonyAction } from './pony'; import { PonyTownGame } from './game'; import { setPonyState, canBoop, isPonyLying, isPonyFlying, isPonyStanding, isPonySitting, getInteractBounds, @@ -8,7 +8,7 @@ import { import { EntityState, Action, Pony, ChatType, EntityFlags, Point, TileType } from '../common/interfaces'; import { FLY_DELAY } from '../common/constants'; import { randomString } from '../common/stringUtils'; -import { pickEntitiesByRect, pickAnyEntities } from '../common/worldMap'; +import { pickEntitiesByRect, pickAnyEntities } from './worldMap'; import { centerPoint } from '../common/rect'; import { pointToWorld, roundPositionX, roundPositionY } from '../common/positionUtils'; import { hammer, shovel } from '../common/entities'; diff --git a/src/ts/common/pony.ts b/src/ts/client/pony.ts similarity index 90% rename from src/ts/common/pony.ts rename to src/ts/client/pony.ts index 521731f..b83111e 100644 --- a/src/ts/common/pony.ts +++ b/src/ts/client/pony.ts @@ -1,46 +1,46 @@ -import { PONY_WIDTH, PONY_HEIGHT, BLINK_FRAMES, canFly } from '../client/ponyUtils'; -import { stand, sneeze, defaultHeadAnimation, defaultBodyFrame, defaultHeadFrame } from '../client/ponyAnimations'; +import { PONY_WIDTH, PONY_HEIGHT, BLINK_FRAMES, canFly } from '../common/ponyUtils'; +import { stand, sneeze } from '../common/ponyAnimations'; import { PaletteSpriteBatch, Pony, BodyAnimation, EntityState, SpriteBatch, ExpressionExtra, HeadAnimation, Palette, PaletteManager, DrawOptions, Rect, EntityFlags, IMap, Entity, DoAction, Muzzle, Expression, getEyeOpenness, Iris, EntityPlayerState, -} from './interfaces'; -import { hasFlag, setFlag } from './utils'; -import { blinkFps, PONY_TYPE } from './constants'; -import { releasePalettes } from './ponyInfo'; -import { createAnEntity, boopSplashRight, boopSplashLeft } from './entities'; +} from '../common/interfaces'; +import { hasFlag, setFlag } from '../common/utils'; +import { blinkFps, PONY_TYPE } from '../common/constants'; +import { createAnEntity, boopSplashRight, boopSplashLeft } from '../common/entities'; import { createAnimationPlayer, isAnimationPlaying, drawAnimation, playAnimation, updateAnimation, playOneOfAnimations -} from './animationPlayer'; -import { blushColor, WHITE, MAGIC_ALPHA, HEARTS_COLOR } from './colors'; -import { encodeExpression, decodeExpression } from './encoders/expressionEncoder'; -import { toScreenX, toWorldX, toWorldY, toScreenYWithZ } from './positionUtils'; -import { getPonyAnimationFrame, getHeadY, drawPony, getPonyHeadPosition, createHeadTransform } from '../client/ponyDraw'; +} from '../common/animationPlayer'; +import { blushColor, WHITE, MAGIC_ALPHA, HEARTS_COLOR } from '../common/colors'; +import { encodeExpression, decodeExpression } from '../common/encoders/expressionEncoder'; +import { toScreenX, toWorldX, toWorldY, toScreenYWithZ } from '../common/positionUtils'; +import { drawPony, getPonyHeadPosition, createHeadTransform } from './ponyDraw'; import { isPonySitting, isPonyFlying, isPonyLying, isPonyStanding, isPonyLandedOrCanLand, isIdle, isIdleAnimation, - isFacingRight, releaseEntity -} from './entityUtils'; + isFacingRight, releaseEntity, + addOrRemoveFromEntityList, + releasePalettePonyInfo +} from '../common/entityUtils'; import { getAnimation, getAnimationFrame, setAnimatorState, updateAnimator, createAnimator, AnimatorState, resetAnimatorState -} from './animator'; +} from '../common/animator'; import { trotting, flying, hovering, toBoopState, isFlyingUpOrDown, isFlyingDown, isSittingDown, isSittingUp, swinging, standing, sitting, lying, swimming, isSwimmingState, swimmingToFlying, toKissState, -} from '../client/ponyStates'; -import { decodePonyInfo } from './compressPony'; -import { defaultPonyState, defaultDrawPonyOptions, isStateEqual } from '../client/ponyHelpers'; +} from '../common/ponyStates'; +import { decodePonyInfo } from '../common/compressPony'; +import { defaultPonyState, defaultDrawPonyOptions, isStateEqual } from '../common/ponyHelpers'; import { sneezeAnimation, holdPoofAnimation, heartsAnimation, tearsAnimation, cryAnimation, zzzAnimations, magicAnimation -} from '../client/spriteAnimations'; -import { rect } from './rect'; -import { addOrRemoveFromEntityList } from './worldMap'; -import { hasDrawLight, hasLightSprite } from '../client/draw'; -import { ponyColliders, ponyCollidersBounds } from './mixins'; -import { PonyTownGame } from '../client/game'; -import { playEffect } from '../client/handlers'; +} from './spriteAnimations'; +import { rect } from '../common/rect'; +import { hasDrawLight, hasLightSprite } from './draw'; +import { ponyColliders, ponyCollidersBounds } from '../common/mixins'; +import { PonyTownGame } from './game'; +import { playEffect } from './handlers'; import * as sprites from '../generated/sprites'; -import { withAlpha } from './color'; +import { withAlpha } from '../common/color'; const flyY = 15; const lightExtentX = 100; @@ -125,10 +125,6 @@ export function createPony( return pony; } -export function isPony(entity: Entity): entity is Pony { - return entity.type === PONY_TYPE; -} - export function isPonyOnTheGround(pony: Pony) { return !isPonyFlying(pony) && !isFlyingUpOrDown(pony.animator.state); } @@ -137,14 +133,6 @@ export function getPaletteInfo(pony: Pony) { return ensurePonyInfoDecoded(pony); } -export function releasePony(pony: Pony) { - if (pony.ponyState.holding) { - releaseEntity(pony.ponyState.holding); - } - - releasePalettePonyInfo(pony); -} - export function canPonyFly(pony: Pony) { return !!pony.palettePonyInfo && canFly(pony.palettePonyInfo); } @@ -165,22 +153,6 @@ export function canPonyFlyUp(pony: Pony) { return !isPonyFlying(pony) && canPonyFly(pony) && !isFlyingUpOrDown(pony.animator.state); } -export function getPonyChatHeight(pony: Pony) { - const baseHeight = 2; - const state = pony.ponyState; - - if (pony.animator.state === trotting) { - return baseHeight; - } else if (pony.animator.state === flying || pony.animator.state === hovering) { - return baseHeight - 16; - } else { - const frame = getPonyAnimationFrame(state.animation, state.animationFrame, defaultBodyFrame); - const animation = state.headAnimation || defaultHeadAnimation; - const headFrame = getPonyAnimationFrame(animation, state.headAnimationFrame, defaultHeadFrame); - return baseHeight + getHeadY(frame, headFrame); - } -} - export function updatePonyInfo(pony: Pony, info: string | Uint8Array, apply: () => void) { pony.info = info; @@ -671,13 +643,6 @@ function transformBatch(batch: SpriteBatch | PaletteSpriteBatch, entity: Entity) batch.scale(isFacingRight(entity) ? -1 : 1, 1); } -function releasePalettePonyInfo(pony: Pony) { - if (pony.palettePonyInfo !== undefined) { - releasePalettes(pony.palettePonyInfo); - pony.palettePonyInfo = undefined; - } -} - function makeLightBounds({ x, y, w, h }: Rect) { return rect(x - lightExtentX, y - lightExtentY, w + lightExtentX * 2, h + lightExtentY * 2); } diff --git a/src/ts/client/ponyDraw.ts b/src/ts/client/ponyDraw.ts index d78eabb..4b22e1f 100644 --- a/src/ts/client/ponyDraw.ts +++ b/src/ts/client/ponyDraw.ts @@ -8,14 +8,14 @@ import { WHITE, SHINES_COLOR, FAR_COLOR, TRANSPARENT, fillToOutlineColor } from import { toInt, hasFlag, repeat, flatten, point } from '../common/utils'; import * as sprites from '../generated/sprites'; import * as offsets from '../common/offsets'; -import { defaultHeadAnimation, defaultBodyFrame, defaultHeadFrame } from './ponyAnimations'; +import { defaultHeadAnimation, defaultBodyFrame, defaultHeadFrame } from '../common/ponyAnimations'; import { toWorldX, toWorldY } from '../common/positionUtils'; import { frontHooves, PONY_WIDTH, PONY_HEIGHT, wings, chestBehind, tails, chest, neckAccessories, waistAccessories, SLEEVED_ACCESSORIES, blinkFrames, flipIris, claws, Sets, backAccessories, SLEEVED_BACK_ACCESSORIES, CHEST_ACCESSORIES_IN_FRONT, flipFaceAccessoryType, flipFaceAccessoryPattern, backLegSleeves, NO_MANE_HEAD_ACCESSORIES, backHoovesInFront, frontHoovesInFront -} from './ponyUtils'; +} from '../common/ponyUtils'; import { HEAD_ACCESSORY_OFFSETS, EAR_ACCESSORY_OFFSETS, EXTRA_ACCESSORY_OFFSETS } from '../common/offsets'; import { createMat2D, identityMat2D, translateMat2D, copyMat2D, rotateMat2D, scaleMat2D } from '../common/mat2d'; import { darkenForOutline } from '../common/ponyInfo'; @@ -126,11 +126,6 @@ export function createHeadTransform( return headTransform; } -export function getHeadY(frame: BodyAnimationFrame, headFrame: HeadAnimationFrame): number { - const headOffset = offsets.headOffsets[frame.body]; - return frame.bodyY + frame.headY + headFrame.headY + headOffset.y; -} - const defaultShadow: BodyShadow = { frame: 0, offset: 0 }; const hairOffsets = [ 0, 0, 0, 0, diff --git a/src/ts/common/worldMap.ts b/src/ts/client/worldMap.ts similarity index 78% rename from src/ts/common/worldMap.ts rename to src/ts/client/worldMap.ts index 8c70662..f3fd58c 100644 --- a/src/ts/common/worldMap.ts +++ b/src/ts/client/worldMap.ts @@ -1,26 +1,27 @@ import { - Entity, Point, TileType, Rect, MapInfo, Camera, Region, IMap, MapState, defaultMapState, Pony, - MapType, EntityFlags, WorldMap, Weather, EntityState, canWalk, MapFlags, -} from './interfaces'; -import { contains, removeItem, boundsIntersect, array, pushUniq, containsPoint, removeItemFast } from './utils'; -import { isBoundsVisible, } from './camera'; + Entity, Point, TileType, Rect, MapInfo, Camera, Region, MapState, defaultMapState, Pony, + MapType, EntityFlags, WorldMap, Weather, EntityState, MapFlags, +} from '../common/interfaces'; +import { contains, removeItem, boundsIntersect, array, pushUniq, containsPoint, removeItemFast } from '../common/utils'; +import { isBoundsVisible, } from '../common/camera'; import { - getRegionTile, setRegionTile, setRegionTileDirty, getRegionElevation, setRegionElevation, - getRegionTileIndex, worldToRegionX, worldToRegionY, generateRegionCollider, invalidateRegionsCollider -} from './region'; -import { weatherRain, splash } from './entities'; -import { releaseEntity, isMoving, isHidden, isDrawable, isPonyFlying } from './entityUtils'; -import { updatePonyEntity, invalidatePalettesForPony, ensurePonyInfoDecoded, isPony, isPonyOnTheGround } from './pony'; -import { getTileHeight, updateTileIndices, isInWater } from '../client/tileUtils'; -import { toScreenX, toScreenY, toScreenYWithZ, rectToScreen, toWorldZ } from './positionUtils'; -import { hasDrawLight, hasLightSprite } from '../client/draw'; -import { PonyTownGame } from '../client/game'; -import { WATER_FPS, PONY_TYPE, REGION_SIZE } from './constants'; -import { updatePosition, canCollideWith } from './collision'; + getRegionElevation, setRegionElevation, + worldToRegionX, worldToRegionY, generateRegionCollider, invalidateRegionsCollider, + getRegionGlobal, getRegion, doRelativeToRegion +} from '../common/region'; +import { weatherRain, splash } from '../common/entities'; +import { releaseEntity, isMoving, isHidden, isDrawable, isPonyFlying, isPony } from '../common/entityUtils'; +import { updatePonyEntity, invalidatePalettesForPony, ensurePonyInfoDecoded, isPonyOnTheGround } from './pony'; +import { getTileHeight, updateTileIndices, getTile, setTile, getTileIndex2, setTilesDirty, isInWaterAt } from '../common/tileUtils'; +import { toScreenX, toScreenY, toScreenYWithZ, rectToScreen, toWorldZ } from '../common/positionUtils'; +import { hasDrawLight, hasLightSprite } from './draw'; +import { PonyTownGame } from './game'; +import { WATER_FPS, PONY_TYPE, REGION_SIZE } from '../common/constants'; +import { updatePosition, canCollideWith } from '../common/collision'; import { PaletteManager } from '../graphics/paletteManager'; -import { timeEnd, timeStart } from '../client/timing'; -import { playEffect } from '../client/handlers'; -import { isFlyingDown } from '../client/ponyStates'; +import { timeEnd, timeStart } from '../common/timing'; +import { playEffect } from './handlers'; +import { isFlyingDown } from '../common/ponyStates'; const defaultMapInfo: MapInfo = { type: MapType.None, @@ -213,62 +214,10 @@ export function removeEntityDirectly(map: WorldMap, entity: Entity) { }); } -export function setTile(map: WorldMap, worldX: number, worldY: number, type: TileType) { - const region = getRegionGlobal(map, worldX, worldY); - - if (!region) - return; - - const x = Math.floor(worldX - region.x * REGION_SIZE); - const y = Math.floor(worldY - region.y * REGION_SIZE); - - const old = getRegionTile(region, x, y); - setRegionTile(region, x, y, type); - - setTilesDirty(map, worldX - 1, worldY - 1, 3, 3); - - if (canWalk(old) !== canWalk(type)) { - setColliderDirty(map, region, x, y); - } -} - -export function setColliderDirty(map: IMap, region: Region, x: number, y: number) { - region.colliderDirty = true; - - if (x === 0) { - const r = getRegionUnsafe(map, region.x - 1, region.y); - r && (r.colliderDirty = true); - } else if (x === (REGION_SIZE - 1)) { - const r = getRegionUnsafe(map, region.x + 1, region.y); - r && (r.colliderDirty = true); - } - - if (y === 0) { - const r = getRegionUnsafe(map, region.x, region.y - 1); - r && (r.colliderDirty = true); - } else if (y === (REGION_SIZE - 1)) { - const r = getRegionUnsafe(map, region.x, region.y + 1); - r && (r.colliderDirty = true); - } -} - export function setTileAtRegion(map: WorldMap, regionX: number, regionY: number, x: number, y: number, type: TileType) { setTile(map, regionX * REGION_SIZE + x, regionY * REGION_SIZE + y, type); } -export function setTilesDirty(map: IMap, ox: number, oy: number, w: number, h: number) { - for (let y = 0; y < h; y++) { - for (let x = 0; x < w; x++) { - doRelativeToRegion(map, x + ox, y + oy, (region, x, y) => setRegionTileDirty(region, x, y)); - } - } -} - -function getTileIndex(map: IMap, x: number, y: number) { - const region = getRegionGlobal(map, x, y); - return region ? getRegionTileIndex(region, x - region.x * REGION_SIZE, y - region.y * REGION_SIZE) : 0; -} - export function getElevation(map: WorldMap, x: number, y: number) { const region = getRegionGlobal(map, x, y); return region ? getRegionElevation(region, x - region.x * REGION_SIZE, y - region.y * REGION_SIZE) : 0; @@ -311,18 +260,6 @@ function updateMinMaxRegion(map: WorldMap) { map.maxRegionY = Math.min(map.maxRegionY, map.regionsY - 1); } -function doRelativeToRegion( - map: IMap, x: number, y: number, action: (region: Region, x: number, y: number) => void -) { - const region = getRegionGlobal(map, x, y); - - if (region) { - const regionX = Math.floor(x - region.x * REGION_SIZE); - const regionY = Math.floor(y - region.y * REGION_SIZE); - action(region, regionX, regionY); - } -} - function addEntityToRegion(region: Region, entity: Entity, map: WorldMap) { region.entities.push(entity); @@ -437,50 +374,6 @@ function removeEntityFromMapRegion(map: WorldMap, entity: Entity) { forEachRegion(map, region => !removeEntityFromRegion(region, entity, map)); } -export function getTile(map: IMap, x: number, y: number): TileType { - const region = getRegionGlobal(map, x, y) as any as Region; - - if (region) { - const regionX = Math.floor(x - region.x * REGION_SIZE); - const regionY = Math.floor(y - region.y * REGION_SIZE); - return getRegionTile(region, regionX, regionY); - } else { - return TileType.None; - } -} - -export function getRegionGlobal(map: IMap, x: number, y: number): T { - const rx = worldToRegionX(x, map); - const ry = worldToRegionY(y, map); - return getRegion(map, rx, ry); -} - -export function getRegion(map: IMap, x: number, y: number): T { - if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) { - throw new Error(`Invalid region coords (${x}, ${y})`); - } else { - return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0]; - } -} - -export function getRegionUnsafe(map: IMap, x: number, y: number): T | undefined { - if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) { - return undefined; - } else { - return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0]; - } -} - -export function addOrRemoveFromEntityList(list: Entity[], entity: Entity, had: boolean, has: boolean) { - if (had !== has) { - if (has) { - pushUniq(list, entity); - } else { - removeItemFast(list, entity); - } - } -} - export function updateEntitiesWithNames(map: WorldMap, hover: Point, player: Entity) { for (let i = map.entitiesWithNames.length - 1; i >= 0; i--) { const entity = map.entitiesWithNames[i]; @@ -562,11 +455,7 @@ export function updateMap(map: WorldMap, delta: number) { } export function getMapHeightAt(map: WorldMap, x: number, y: number, gameTime: number) { - return getTileHeight(getTile(map, x, y), getTileIndex(map, x, y), x, y, gameTime, map.type); -} - -export function isInWaterAt(map: IMap, x: number, y: number) { - return getTile(map, x, y) === TileType.Water && isInWater(getTileIndex(map, x, y), x, y); + return getTileHeight(getTile(map, x, y), getTileIndex2(map, x, y), x, y, gameTime, map.type); } export function updateEntities(game: PonyTownGame, gameTime: number, delta: number, safe: boolean) { diff --git a/src/ts/common/adminUtils.ts b/src/ts/common/adminUtils.ts index be8c3e4..50968e6 100644 --- a/src/ts/common/adminUtils.ts +++ b/src/ts/common/adminUtils.ts @@ -1,15 +1,13 @@ import * as moment from 'moment'; -import { escape, escapeRegExp, startsWith, range, uniq, compact } from 'lodash'; +import { escapeRegExp, startsWith, range, uniq, compact } from 'lodash'; import { fromNow, toInt, hasFlag, compareDates, removeItem, includes } from './utils'; import { DAY } from './constants'; import { - Account, OriginInfo, Document, OriginRef, SupporterFlags, BannedMuted, AccountBase, LogEntry, + Account, OriginInfo, Document, OriginRef, SupporterFlags, BannedMuted, AccountBase, DuplicateResult, DuplicateBase, Duplicate, Auth, MergeInfo } from './adminInterfaces'; import { hasRole } from './accountUtils'; import { filterBadWordsPartial } from './swears'; -import { faPlusCircle, faClock, faMinusCircle, faCaretSquareUp, faCaretSquareDown } from '../client/icons'; -import { element, textNode } from '../client/htmlUtils'; interface UpdatedAt { updatedAt: Date; @@ -52,108 +50,6 @@ export function getAge(birthdate: Date) { // chat & events -function enc(text?: string): string { - return escape(text || ''); -} - -function encWithHighlight(text?: string): string { - return highlightWords(enc(text || '')); -} - -export function formatEventDesc(text: string): string { - return encWithHighlight(text).replace(/\[([a-z0-f]{24})\]/g, `[$1]`); -} - -function getMessageTag(message: string) { - if (/^\/p /.test(message)) { - return 'party'; - } else if (/^\/w /.test(message)) { - return 'whisper'; - } else if (/^\/s[s123] /.test(message)) { - return 'supporter'; - } else if (/^\//.test(message)) { - return 'command'; - } else { - return 'none'; - } -} - -export function replaceSwears(element: HTMLElement) { - const text = element.textContent; - - if (text) { - const replaced = encWithHighlight(text); - - if (text !== replaced) { - element.innerHTML = replaced; - } - } -} - -function formatChatLine(l: string): HTMLElement { - // 00:00:01 [system] Timed out for swearing - // 00:00:01 [patreon] fetched patreon data - // 00:00:01 [dev][Autumn Leafs] hello world - // 00:00:01 [dev][Autumn Leafs][muted] hello world - // 00:00:01 [dev][Autumn Leafs][ignored] hello world - // 00:00:01 [dev-pl][Autumn Leafs][ignored] hello world - // 00:00:01 [57a3dc6f2f0019a161cdebf6][dev][Autumn Leafs][ignored] hello world - // 00:00:01 [1][dev][Autumn Leafs][ignored] hello world - // 00:00:01 [1:merged][dev][Autumn Leafs][ignored] hello world - // 00:00:01 [merged][dev][Autumn Leafs][ignored] hello world - // 00:00:01 [merged][dev][main][Autumn Leafs][ignored] hello world - - /* tslint:disable:max-line-length */ - const regex = /^([0-9:]+) (\[(?:merged|\d+|\d+:merged|[a-z0-9]{24})\])?\[([a-z0-9_-]+)\](?:\[([a-z0-9_-]+)\])?((?:\[.*?\])?)(?:\[(muted|ignored|ignorepub)\])?\t(.*)$/; - const m = regex.exec(l); - - if (m) { - const [, time, accountId, server, map, name, mutedIgnored, message] = m; - const messageTag = server === 'system' ? 'system' : getMessageTag(message); - const modTag = mutedIgnored ? ' message-muted' : ''; - - return element('div', 'chatlog-line', [ - element('span', 'time', [], { 'data-text': time }), - accountId ? element('span', 'account-id', [textNode(accountId)]) : undefined, - element('span', `server server-${server.replace(/-.+$/g, '')}`, [textNode(`[${server}]`)]), - map ? element('span', `map map-${map}`, [textNode(`[${map}]`)]) : undefined, - element('span', mutedIgnored ? `name ${mutedIgnored}` : `name`, [textNode(name)]), - textNode(' '), - element('span', `message message-${messageTag}${modTag}`, [textNode(message)]), - textNode(' '), - element('a', 'chat-translate', [], undefined, { click: translateChat }), - ]); - } else { - return element('div', '', [textNode(highlightWords(l))]); - } -} - -function translateChat(this: HTMLElement) { - const lines: string[] = []; - let parent = this.parentElement; - - for (let i = 0; parent && i < 10; i++) { - lines.push(parent.querySelector('.message')!.textContent!); - parent = parent.nextElementSibling as HTMLElement; - } - - window.open(`https://translate.google.com/#auto/en/${encodeURIComponent(lines.join('\n'))}`); -} - -if (typeof window !== 'undefined') { - (window as any).goToAccount = (accountId: string) => { - window.dispatchEvent(new CustomEvent('go-to-account', { detail: accountId })); - }; -} - -export function formatChat(chat: string): HTMLElement[] { - return (chat || '') - .trim() - .split(/\r?\n/g) - .reverse() - .map(formatChatLine); -} - export interface ChatDate { value: string; label: string; @@ -483,38 +379,6 @@ export interface SupporterChange { class: string; } -export function createSupporterChanges(entries: LogEntry[]): SupporterChange[] { - const changes = entries.map(l => ({ - message: l.message, - level: +((/\d+/.exec(l.message) || ['0'])[0]), - added: /added/i.test(l.message), - date: new Date(l.date), - icon: /added/i.test(l.message) ? faPlusCircle : (/decline/i.test(l.message) ? faClock : faMinusCircle), - class: /added/i.test(l.message) ? 'text-success' : (/decline/i.test(l.message) ? 'text-warning' : 'text-danger'), - })); - - for (let i = 1; i < changes.length; i++) { - const prev = changes[i - 1]; - const current = changes[i]; - - if (current.date.getMonth() !== prev.date.getMonth()) { - current.class += ' border-left border-success pl-2'; - } - - if (current.added && prev.added) { - if (current.level > prev.level) { - current.icon = faCaretSquareUp; - current.class = 'text-info'; - } else if (current.level < prev.level) { - current.icon = faCaretSquareDown; - current.class = 'text-info'; - } - } - } - - return changes; -} - export function getIdsFromNote(note: string | undefined) { return note ? uniq(note.match(/[0-9a-f]{24}/g)) : []; } diff --git a/src/ts/client/canvasUtils.ts b/src/ts/common/canvasUtils.ts similarity index 100% rename from src/ts/client/canvasUtils.ts rename to src/ts/common/canvasUtils.ts diff --git a/src/ts/common/clientActionsTemplte.ts b/src/ts/common/clientActionsTemplte.ts new file mode 100644 index 0000000..bd212a4 --- /dev/null +++ b/src/ts/common/clientActionsTemplte.ts @@ -0,0 +1,53 @@ +import { Method, SocketClient, Bin } from 'ag-sockets/dist/browser'; +import { + MapInfo, WorldState, PartyFlags, Action, NotificationFlags, LeaveReason, + SayData, MapState, PonyData, FriendStatusData} from '../common/interfaces'; +const BinEntityId = Bin.U32; +const BinEntityPlayerState = Bin.U8; +const BinNotificationId = Bin.U16; +const BinSayDatas = [BinEntityId, Bin.Str, Bin.U8]; + +export class ClientActionsTemplate implements SocketClient { + + @Method({ binary: [Bin.U32] }) + queue(_place: number) {} + @Method({ binary: [Bin.Obj, Bin.Bool] }) + worldState(_state: WorldState, _initial: boolean) { } + @Method({ binary: [Bin.Obj, Bin.Obj] }) + mapState(_info: MapInfo, _state: MapState) { } + @Method({ binary: [Bin.Obj] }) + mapUpdate(_state: MapState) {} + @Method({ binary: [] }) + mapSwitching() { } + @Method({ binary: [Bin.I32, Bin.I32, Bin.U8Array] }) + mapTest(_width: number, _height: number, _buffer: Uint8Array) { } + @Method({ binary: [BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U16] }) + myEntity(_id: number, _name: string, _info: string, _characterId: string, _crc: number) {} + @Method({ binary: [[Bin.U8], [Bin.U8Array], Bin.U8Array, [Bin.U8Array], BinSayDatas] }) + update(_unsubscribes: number[], _subscribes: Uint8Array[], _updates: Uint8Array | null, _regions: Uint8Array[], _says: SayData[]) {} + @Method({ binary: [Bin.F32, Bin.F32, Bin.Bool] }) + fixPosition(_x: number, _y: number, _safe: boolean) {} + @Method({ binary: [BinEntityId, Bin.U8, Bin.Obj] }) + actionParam(_id: number, _action: Action, _param: any) {} + @Method({ binary: [Bin.U8] }) + left(_reason: LeaveReason) {} + @Method({ binary: [BinNotificationId, BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U8] }) + addNotification(_id: number, _entityId: number, _name: string, _message: string, _note: string, _flags: NotificationFlags) {} + + @Method({ binary: [BinNotificationId] }) + removeNotification(_id: number) { } + @Method({ binary: [BinEntityId, BinEntityId] }) + updateSelection(_currentId: number, _newId: number) {} + @Method({ binary: [[BinEntityId, Bin.U8]] }) + updateParty(_party: [number, PartyFlags][] | undefined) {} + @Method({ binary: [[BinEntityId, Bin.Obj, Bin.U8Array, Bin.U8Array, BinEntityPlayerState, Bin.Bool]] }) + updatePonies(_ponies: PonyData[]) {} + @Method({ binary: [Bin.Obj, Bin.Bool] }) + updateFriends(_friends: FriendStatusData[], _removeMissing: boolean) {} + @Method({ binary: [BinEntityId, Bin.Str, Bin.U32, Bin.Bool] }) + entityInfo(_id: number, _name: string, _crc: number, _nameBad: boolean) {} + @Method({ binary: [Bin.Obj] }) + entityList(_value: { name: string; x: number; y: number; }[]) {} + @Method({ binary: [Bin.Obj] }) + testPositions(_data: { frame: number; x: number | undefined; y: number | undefined; moved: boolean; }[]) {} +} diff --git a/src/ts/common/clientAdminActionsTemplate.ts b/src/ts/common/clientAdminActionsTemplate.ts new file mode 100644 index 0000000..936d5aa --- /dev/null +++ b/src/ts/common/clientAdminActionsTemplate.ts @@ -0,0 +1,15 @@ +import { Method } from 'ag-sockets'; +import { ModelTypes } from './adminInterfaces'; + +export interface ClientUpdate { + type: ModelTypes; + id: string; + update: any; +} + +export class ClientAdminActionsTemplate { + connected() {} + disconnected() {} + @Method() + updates(_updates: ClientUpdate[]) {} +} diff --git a/src/ts/common/collision.ts b/src/ts/common/collision.ts index e933864..cadccb0 100644 --- a/src/ts/common/collision.ts +++ b/src/ts/common/collision.ts @@ -1,9 +1,10 @@ import { Entity, IMap, Region, EntityFlags } from './interfaces'; import { clamp } from './utils'; import { toWorldX, toWorldY } from './positionUtils'; -import { getRegionGlobal, isInWaterAt } from './worldMap'; import { tileWidth, tileHeight, PONY_TYPE, REGION_SIZE, REGION_WIDTH, REGION_HEIGHT } from './constants'; import { isInTheAir, isFlying } from './entityUtils'; +import { getRegionGlobal, getRegionUnsafe } from './region'; +import { isInWaterAt } from './tileUtils'; export function isOutsideMap(x: number, y: number, map: IMap): boolean { return x < 0 || y < 0 || x >= map.width || y >= map.height; @@ -294,3 +295,23 @@ export function updatePosition(entity: Entity, delta: number, map: IMap, region: Region, x: number, y: number) { + region.colliderDirty = true; + + if (x === 0) { + const r = getRegionUnsafe(map, region.x - 1, region.y); + r && (r.colliderDirty = true); + } else if (x === (REGION_SIZE - 1)) { + const r = getRegionUnsafe(map, region.x + 1, region.y); + r && (r.colliderDirty = true); + } + + if (y === 0) { + const r = getRegionUnsafe(map, region.x, region.y - 1); + r && (r.colliderDirty = true); + } else if (y === (REGION_SIZE - 1)) { + const r = getRegionUnsafe(map, region.x, region.y + 1); + r && (r.colliderDirty = true); + } +} diff --git a/src/ts/common/compressPony.ts b/src/ts/common/compressPony.ts index 5d648b5..1ca4985 100644 --- a/src/ts/common/compressPony.ts +++ b/src/ts/common/compressPony.ts @@ -5,13 +5,13 @@ import { syncLockedPonyInfoNumber, syncLockedPonyInfo, createBasePony, toPalette import { bitWriter, bitReader, ReadBits, WriteBits, countBits, numberToBitCount } from './bitUtils'; import { BLACK, WHITE, TRANSPARENT } from './colors'; import { at, toInt, pushUniq, array, clamp, includes, att } from './utils'; -import { getColorCount } from '../client/spriteUtils'; +import { getColorCount } from './spriteUtils'; import * as sprites from '../generated/sprites'; import { parseColorFast, colorToHexRGB } from './color'; import { SLEEVED_ACCESSORIES, frontHooves, mergedFacialHair, mergedBackAccessories, mergedManes, mergedBackManes, mergedExtraAccessories, mergedHeadAccessories -} from '../client/ponyUtils'; +} from './ponyUtils'; import { CM_SIZE } from './constants'; export const VERSION = 5; // previous: 3 diff --git a/src/ts/client/emoji.ts b/src/ts/common/emoji.ts similarity index 97% rename from src/ts/client/emoji.ts rename to src/ts/common/emoji.ts index 3cc9c8f..650bdb8 100644 --- a/src/ts/client/emoji.ts +++ b/src/ts/common/emoji.ts @@ -1,10 +1,10 @@ import { escape } from 'lodash'; -import { Sprite } from '../common/interfaces'; +import { Sprite } from './interfaces'; import { canvasToSource } from './canvasUtils'; import { drawCanvas } from '../graphics/contextSpriteBatch'; -import { WHITE } from '../common/colors'; +import { WHITE } from './colors'; import { normalSpriteSheet } from '../generated/sprites'; -import { includes } from '../common/utils'; +import { includes } from './utils'; export interface Emoji { names: string[]; diff --git a/src/ts/common/entityUtils.ts b/src/ts/common/entityUtils.ts index 8baaa32..786820d 100644 --- a/src/ts/common/entityUtils.ts +++ b/src/ts/common/entityUtils.ts @@ -1,16 +1,35 @@ import { sort } from 'timsort'; import { - Entity, EntityState, BodyAnimation, Point, EntityFlags, IMap, Pony, Says, EntityPlayerState, WorldMap + Entity, EntityState, BodyAnimation, Point, EntityFlags, IMap, Pony, Says, EntityPlayerState, WorldMap, + BodyAnimationFrame, + HeadAnimationFrame } from './interfaces'; -import { hasFlag, distance, pushUniq, setFlag } from './utils'; -import { stand, sit, lie, fly, flyBug, swim } from '../client/ponyAnimations'; -import { releasePony, isPony } from './pony'; +import { hasFlag, distance, pushUniq, setFlag, removeItemFast } from './utils'; +import { stand, sit, lie, fly, flyBug, swim, defaultBodyFrame, defaultHeadAnimation, defaultHeadFrame } from './ponyAnimations'; import { toScreenX, toScreenY } from './positionUtils'; import { releasePalette } from '../graphics/paletteManager'; import { rect } from './rect'; -import { addOrRemoveFromEntityList } from './worldMap'; import { PONY_TYPE } from './constants'; import { isStaticCollision } from './collision'; +import { releasePalettes } from './ponyInfo'; +import { trotting, flying, hovering } from './ponyStates'; +import * as offsets from './offsets'; + + +export function releasePalettePonyInfo(pony: Pony) { + if (pony.palettePonyInfo !== undefined) { + releasePalettes(pony.palettePonyInfo); + pony.palettePonyInfo = undefined; + } +} + +export function releasePony(pony: Pony) { + if (pony.ponyState.holding) { + releaseEntity(pony.ponyState.holding); + } + + releasePalettePonyInfo(pony); +} export function releaseEntity(entity: Entity) { if (isPony(entity)) { @@ -24,6 +43,31 @@ export function releaseEntity(entity: Entity) { } } +export function getPonyAnimationFrame({ frames }: { frames: T[] }, frame: number, defaultFrame: T): T { + return frames.length > 0 ? frames[Math.max(0, frame) % frames.length] : defaultFrame; +} + +export function getPonyChatHeight(pony: Pony) { + const baseHeight = 2; + const state = pony.ponyState; + + if (pony.animator.state === trotting) { + return baseHeight; + } else if (pony.animator.state === flying || pony.animator.state === hovering) { + return baseHeight - 16; + } else { + const frame = getPonyAnimationFrame(state.animation, state.animationFrame, defaultBodyFrame); + const animation = state.headAnimation || defaultHeadAnimation; + const headFrame = getPonyAnimationFrame(animation, state.headAnimationFrame, defaultHeadFrame); + return baseHeight + getHeadY(frame, headFrame); + } +} + +export function getHeadY(frame: BodyAnimationFrame, headFrame: HeadAnimationFrame): number { + const headOffset = offsets.headOffsets[frame.body]; + return frame.bodyY + frame.headY + headFrame.headY + headOffset.y; +} + export function addChatBubble(map: WorldMap, entity: Entity, says: Says) { entity.says = says; pushUniq(map.entitiesWithChat, entity); @@ -235,3 +279,17 @@ export function isDecal(entity: Entity) { export function isCritter(entity: Entity) { return (entity.flags & EntityFlags.Critter) !== 0; } + +export function addOrRemoveFromEntityList(list: Entity[], entity: Entity, had: boolean, has: boolean) { + if (had !== has) { + if (has) { + pushUniq(list, entity); + } else { + removeItemFast(list, entity); + } + } +} + +export function isPony(entity: Entity): entity is Pony { + return entity.type === PONY_TYPE; +} diff --git a/src/ts/client/fonts.ts b/src/ts/common/fonts.ts similarity index 100% rename from src/ts/client/fonts.ts rename to src/ts/common/fonts.ts diff --git a/src/ts/client/ponyAnimations.ts b/src/ts/common/ponyAnimations.ts similarity index 99% rename from src/ts/client/ponyAnimations.ts rename to src/ts/common/ponyAnimations.ts index 9fe8170..a84e00f 100644 --- a/src/ts/client/ponyAnimations.ts +++ b/src/ts/common/ponyAnimations.ts @@ -1,5 +1,5 @@ -import { BodyAnimation, BodyAnimationFrame, HeadAnimation, HeadAnimationFrame, BodyShadow, HeadAnimationProperties } from '../common/interfaces'; -import { repeat, flatten } from '../common/utils'; +import { BodyAnimation, BodyAnimationFrame, HeadAnimation, HeadAnimationFrame, BodyShadow, HeadAnimationProperties } from './interfaces'; +import { repeat, flatten } from './utils'; // body animations diff --git a/src/ts/client/ponyHelpers.ts b/src/ts/common/ponyHelpers.ts similarity index 93% rename from src/ts/client/ponyHelpers.ts rename to src/ts/common/ponyHelpers.ts index 2030a68..e93b71e 100644 --- a/src/ts/client/ponyHelpers.ts +++ b/src/ts/common/ponyHelpers.ts @@ -1,5 +1,5 @@ -import { DrawPonyOptions, NoDraw, PonyState, PonyStateFlags } from '../common/interfaces'; -import { SHADOW_COLOR, blushColor } from '../common/colors'; +import { DrawPonyOptions, NoDraw, PonyState, PonyStateFlags } from './interfaces'; +import { SHADOW_COLOR, blushColor } from './colors'; import { stand } from './ponyAnimations'; const defaultBlushColor = blushColor(0); diff --git a/src/ts/common/ponyInfo.ts b/src/ts/common/ponyInfo.ts index 2fdc198..7b86dc2 100644 --- a/src/ts/common/ponyInfo.ts +++ b/src/ts/common/ponyInfo.ts @@ -11,7 +11,7 @@ import { BLACK, fillToOutline, fillToOutlineColor, WHITE, TRANSPARENT, fillToOut import { mergedManes, mergedBackManes, mergedFacialHair, mergedEarAccessories, mergedChestAccessories, SLEEVED_ACCESSORIES, mergedBackAccessories, mergedExtraAccessories, mergedHeadAccessories -} from '../client/ponyUtils'; +} from './ponyUtils'; const MAX_COLORS = 6; const FILLS = ['1e90ff', '32cd32', 'da70d6', 'dc143c', '7fffd4']; diff --git a/src/ts/client/ponyStates.ts b/src/ts/common/ponyStates.ts similarity index 98% rename from src/ts/client/ponyStates.ts rename to src/ts/common/ponyStates.ts index b5ff9a0..5e573df 100644 --- a/src/ts/client/ponyStates.ts +++ b/src/ts/common/ponyStates.ts @@ -1,11 +1,11 @@ -import { animatorState as state, animatorTransition as transition, anyState, AnimatorState } from '../common/animator'; +import { animatorState as state, animatorTransition as transition, anyState, AnimatorState } from './animator'; import { stand, sit, sitDown, standUp, lie, lieDown, sitUp, flyBug, fly, flyUp, flyDown, flyUpBug, flyDownBug, trot, boop, boopSit, swim, sitToTrot, lieToTrot, boopLie, trotToFly, trotToFlyBug, boopFly, boopFlyBug, flyToTrot, flyToTrotBug, swing, swimToTrot, trotToSwim, swimToFly, flyToSwim, boopSwim, swimToFlyBug, flyToSwimBug, kissBody, kissLiftHoofBody, kissFlyBody, kissFlyBugBody, kissLieBody, kissSitBody, kissSwimBody, kissToTrot } from './ponyAnimations'; -import { BodyAnimation } from '../common/interfaces'; +import { BodyAnimation } from './interfaces'; function n(value: string) { return (DEVELOPMENT || SERVER) ? value : ''; diff --git a/src/ts/client/ponyUtils.ts b/src/ts/common/ponyUtils.ts similarity index 98% rename from src/ts/client/ponyUtils.ts rename to src/ts/common/ponyUtils.ts index 30d468c..5a81c90 100644 --- a/src/ts/client/ponyUtils.ts +++ b/src/ts/common/ponyUtils.ts @@ -3,9 +3,9 @@ import { range, dropRight, compact, max, zip } from 'lodash'; import { Eye, Iris, Muzzle, ExpressionExtra, Sprite, ColorExtraSets, PonyInfoBase, SpriteSetBase, ColorExtra, ColorExtraSet -} from '../common/interfaces'; +} from './interfaces'; import * as sprites from '../generated/sprites'; -import { HEAD_ACCESSORY_OFFSETS, EXTRA_ACCESSORY_OFFSETS, EAR_ACCESSORY_OFFSETS } from '../common/offsets'; +import { HEAD_ACCESSORY_OFFSETS, EXTRA_ACCESSORY_OFFSETS, EAR_ACCESSORY_OFFSETS } from './offsets'; export const PONY_WIDTH = 80; export const PONY_HEIGHT = 70; diff --git a/src/ts/common/region.ts b/src/ts/common/region.ts index 6710e3f..ab6cad7 100644 --- a/src/ts/common/region.ts +++ b/src/ts/common/region.ts @@ -1,7 +1,6 @@ import { TileType, Region, IMap } from './interfaces'; import { clamp } from './utils'; import { tileWidth, tileHeight, REGION_SIZE, REGION_WIDTH, REGION_HEIGHT } from './constants'; -import { getRegion } from './worldMap'; import { toScreenX, toScreenY } from './positionUtils'; import { ponyColliders, ponyCollidersBounds } from './mixins'; import { decompressTiles } from './compress'; @@ -200,3 +199,38 @@ export function generateRegionCollider(region: Reg } } } + + +export function getRegionGlobal(map: IMap, x: number, y: number): T { + const rx = worldToRegionX(x, map); + const ry = worldToRegionY(y, map); + return getRegion(map, rx, ry); +} + +export function getRegion(map: IMap, x: number, y: number): T { + if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) { + throw new Error(`Invalid region coords (${x}, ${y})`); + } else { + return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0]; + } +} + +export function getRegionUnsafe(map: IMap, x: number, y: number): T | undefined { + if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) { + return undefined; + } else { + return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0]; + } +} + +export function doRelativeToRegion( + map: IMap, x: number, y: number, action: (region: Region, x: number, y: number) => void +) { + const region = getRegionGlobal(map, x, y); + + if (region) { + const regionX = Math.floor(x - region.x * REGION_SIZE); + const regionY = Math.floor(y - region.y * REGION_SIZE); + action(region, regionX, regionY); + } +} diff --git a/src/ts/common/sheets.ts b/src/ts/common/sheets.ts index 5f8d0d3..d660492 100644 --- a/src/ts/common/sheets.ts +++ b/src/ts/common/sheets.ts @@ -1,9 +1,9 @@ import { range, times } from 'lodash'; import { PonyInfo, Point, PonyState, DrawPonyOptions, PonyInfoNumber, SpriteSet, PalettePonyInfo, NoDraw } from './interfaces'; import * as offsets from './offsets'; -import { defaultPonyState } from '../client/ponyHelpers'; +import { defaultPonyState } from './ponyHelpers'; import { WHITE, BLACK, ORANGE, BLUE, CYAN, RED } from './colors'; -import { createBodyFrame } from '../client/ponyAnimations'; +import { createBodyFrame } from './ponyAnimations'; import { setFlag, repeat } from './utils'; type OnFrame = (pony: PonyInfoNumber, state: PonyState, options: DrawPonyOptions, x: number, y: number, pattern: number) => void; diff --git a/src/ts/common/spriteUtils.ts b/src/ts/common/spriteUtils.ts new file mode 100644 index 0000000..7bf703a --- /dev/null +++ b/src/ts/common/spriteUtils.ts @@ -0,0 +1,23 @@ +import { ColorExtra, ColorExtraSets, PonyEye, Sprite } from './interfaces'; + +export function createSprite(x: number, y: number, w: number, h: number, ox: number, oy: number, type: number): Sprite { + return { x, y, w, h, ox, oy, type }; +} + +export function addTitles(sprites: ColorExtraSets, titles: string[]): ColorExtraSets { + return sprites && sprites.map((ns, i) => + ns && ns.map(s => s && { color: s.color, colors: s.colors, title: titles[i], label: titles[i] })); +} + +export function addLabels(sprites: ColorExtraSets, labels: string[]) { + sprites && sprites.forEach((s, i) => s && s[0] ? s[0]!.label = labels[i] : undefined); + return sprites; +} + +export function createEyeSprite(eye: PonyEye | undefined, iris: number, defaultPalette: Uint32Array): ColorExtra | undefined { + return eye && { color: eye.irises[iris]!, colors: 2, extra: eye.base, palettes: [defaultPalette] }; +} + +export function getColorCount(sprite: ColorExtra | undefined): number { + return sprite && sprite.colors ? Math.floor((sprite.colors - 1) / 2) : 0; +} diff --git a/src/ts/common/stringUtils.ts b/src/ts/common/stringUtils.ts index 76239b7..2b26bac 100644 --- a/src/ts/common/stringUtils.ts +++ b/src/ts/common/stringUtils.ts @@ -1,3 +1,4 @@ +import { SAY_MAX_LENGTH, PLAYER_NAME_MAX_LENGTH } from './constants'; const lowercaseCharacters = 'abcdefghijklmnopqrstuvwxyz0123456789_'; const uppercaseCharacters = lowercaseCharacters + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const CARRIAGERETURN = '\r'.charCodeAt(0); @@ -88,3 +89,145 @@ export function matcher(regex: RegExp) { export function isVisibleChar(code: number) { return code !== CARRIAGERETURN && !(code >= 0xfe00 && code <= 0xfe0f); } + + +const otherValid = [ + '♂♀⚲⚥⚧☿♁⚨⚩⚦⚢⚣⚤', // gender symbols + '™®♥♦♣♠❥♡♢♤♧ღஐ·´°•◦✿❀◆◇◈◉◊。¥€«»,:■□—', // other + '〈〉「」『』【】《》♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼№●○◌★☆✰✦✧▪▫・', // other 2 + '\u1160\u3000\u3164', // spaces (replaced later) +].join('').split('').reduce((set, c) => (set.add(c.charCodeAt(0)), set), new Set()); + +export function isValid(c: number): boolean { + return (c >= 0x0020 && c <= 0x007e) // latin + || (c >= 0x00a0 && c <= 0x00ff) // latin 1 supplement + || (c >= 0x0100 && c <= 0x017F) // Latin Extended-A + || (c >= 0x0180 && c <= 0x024F) // Latin Extended-B + || (c >= 0x1e00 && c <= 0x1eff) // Latin Extended Additional + || (c >= 0x0370 && c <= 0x03FF) // Greek and Coptic + || (c >= 0x0400 && c <= 0x0481) || (c >= 0x048A && c <= 0x04FF) // cyrillic + || (c >= 0x3041 && c <= 0x3096) // hiragana + || (c >= 0x30A0 && c <= 0x30FF) // hatakana + || (c >= 0x3400 && c <= 0x4DB5) || (c >= 0x4E00 && c <= 0x9FCB) || (c >= 0xF900 && c <= 0xFA6A) // kanji + || (c >= 0x2F00 && c <= 0x2FDF) // Kangxi Radicals + || (c >= 0x3000 && c <= 0x302D) // CJK Symbols and Punctuation + || (c >= 0x1D00 && c <= 0x1D7F) // Phonetic Extensions + || (c >= 0x0250 && c <= 0x02AF) // IPA Extensions + || (c >= 0xA720 && c <= 0xA7FF) // Latin Extended-D + || (c >= 0x0E00 && c <= 0x0E7F) // Thai + || (c >= 0xff01 && c <= 0xff5e) // Romaji (replaced later) + || (c >= 0x2200 && c <= 0x22FF) // Mathematical Operators + || (c >= 0x25A0 && c <= 0x25FF) // Geometric Shapes + || (c >= 0x2600 && c <= 0x26ff) || (c >= 0x2700 && c <= 0x27bf) || (c >= 0x2b00 && c <= 0x2bef) // emoji + || (c >= 0x1f600 && c <= 0x1f64f) || (c >= 0x1f680 && c <= 0x1f6f6) || (c >= 0x1f300 && c <= 0x1f5ff) // emoji + || (c >= 0x231a && c <= 0x231b) || (c >= 0x23e9 && c <= 0x23fa) // emoji + || (c >= 0x1f900 && c <= 0x1f9ff) // Supplemental Symbols and Pictographs + || otherValid.has(c) // other symbols + ; +} + +export function isValid2(c: number): boolean { + return (c >= 0x2b0 && c <= 0x2ff) // Spacing Modifier Letters + || (c >= 0x531 && c <= 0x556) || (c >= 0x559 && c <= 0x55f) || (c >= 0x561 && c <= 0x587) + || (c >= 0x589 && c <= 0x58a) || (c >= 0x58c && c <= 0x58f) // Armenian + || (c >= 0x591 && c <= 0x5c7) || (c >= 0x5d0 && c <= 0x5ea) || (c >= 0x5f0 && c <= 0x5f4) // Hebrew + || (c >= 0x600 && c <= 0x6ff) // Arabic + || (c >= 0x7c0 && c <= 0x7fa) // NKo + || (c >= 0x900 && c <= 0x97f) // Devanagari + || (c === 0xb90) || (c === 0xb9c) // Tamil + || (c >= 0xc85 && c <= 0xc8c) || (c >= 0xc8e && c <= 0xc90) || (c >= 0xc91 && c <= 0xca8) + || (c >= 0xcaa && c <= 0xcb3) || (c >= 0xcb5 && c <= 0xcb9) || (c >= 0xce6 && c <= 0xcef) // Kannada + || (c >= 0x10a0 && c <= 0x10c5) || (c === 0x10c7) || (c === 0x10cd) || (c >= 0x10d0 && c <= 0x10ff) // Georgian + || (c >= 0x1100 && c <= 0x11ff) || (c >= 0x3130 && c <= 0x318f) || (c >= 0xac00 && c <= 0xd7af) // Hangul + || (c >= 0x1400 && c <= 0x167f) // Unified Canadian Aboriginal Syllabics + || (c >= 0x2010 && c <= 0x2027) || (c >= 0x2030 && c <= 0x205e) // General Punctuation + || (c >= 0x20a0 && c <= 0x20bf) // Currency Symbols + || (c >= 0x2100 && c <= 0x214f) // Letterlike Symbols + || (c >= 0x2150 && c <= 0x218b) // Number Forms + || (c >= 0x2300 && c <= 0x239a) || (c >= 0x23b4 && c <= 0x23fa) // Miscellaneous Technical + || (c >= 0x2500 && c <= 0x257f) // Box Drawing + || (c >= 0x2800 && c <= 0x28ff) // Braille Patterns + || (c >= 0x3000 && c <= 0x303f) // CJK Symbols and Punctuation + || (c >= 0x3105 && c <= 0x312d) // Bopomofo + || (c >= 0xfe30 && c <= 0xfe4f) // CJK Compatibility Forms + || (c >= 0xff01 && c <= 0xffef) // Halfwidth and Fullwidth Forms + // || (c >= 0x1f170 && c < 0x1f189) // Enclosed Alphanumeric Supplement [a-z] + || (c >= 0x1f000 && c <= 0x1f02b) // Mahjong Tiles + || (c >= 0x1f0a0 && c <= 0x1f0ae) || (c >= 0x1f0b1 && c <= 0x1f0bf) || (c >= 0x1f0c1 && c <= 0x1f0cf) + || (c >= 0x1f0d1 && c <= 0x1f0df) || (c >= 0x1f0e0 && c <= 0x1f0f5) // Playing Cards + || (c >= 0x1f1e6 && c <= 0x1f1ff) // Enclosed Alphanumeric Supplement (regional indicators) + ; +} + +function isInvalid(c: number): boolean { + return c === 0x1f595 // middle finger emoji + || c === 0x00ad // soft hyphen + ; +} + +function isValidForName(c: number): boolean { + return isValid(c) && !isInvalid(c); +} + +function isValidForMessage(c: number): boolean { + return (isValid(c) || isValid2(c)) && !isInvalid(c); +} + +export const matchRomaji = /[\uff01-\uff5e]/g; + +const matchOtherWhitespace = /[\u1160\u2800\u3000\u3164\uffa0]+/g; + +export function replaceRomaji(match: string): string { + return String.fromCharCode(match.charCodeAt(0) - 0xfee0); +} + +export function cleanName(name: string | undefined): string { + return filterString(name, isValidForName) + .replace(matchOtherWhitespace, ' ') // whitespace characters + .replace(/\s+/g, ' ') + .replace(matchRomaji, replaceRomaji) + .trim(); +} + +export function cleanMessage(text: string | undefined): string { + return filterString(text, isValidForMessage) + .replace(matchOtherWhitespace, ' ') // whitespace characters + .replace(/[\r\n]/g, '') + .replace(matchRomaji, replaceRomaji) + .trim() + .substr(0, SAY_MAX_LENGTH); +} + +export function filterString(value: string | undefined, filter: (code: number) => boolean): string { + value = value || ''; + + for (let i = 0; i < value.length; i++) { + let code = value.charCodeAt(i); + let size = 1; + let invalidSurrogate = false; + + if (isSurrogate(code) && (i + 1) < value.length) { + const extra = value.charCodeAt(i + 1); + + if (isLowSurrogate(extra)) { + code = fromSurrogate(code, extra); + i++; + size++; + } else { + invalidSurrogate = true; + } + } + + if (invalidSurrogate || !filter(code)) { + i -= size; + value = value.substr(0, i + 1) + value.substr(i + size + 1); + } + } + + return value; +} + +export function validatePonyName(name: string | undefined): boolean { + return !!name && !!name.length && name.length <= PLAYER_NAME_MAX_LENGTH && !/^[.,_-]+$/.test(name); +} + diff --git a/src/ts/client/tileUtils.ts b/src/ts/common/tileUtils.ts similarity index 90% rename from src/ts/client/tileUtils.ts rename to src/ts/common/tileUtils.ts index 16d483f..a1fd2c5 100644 --- a/src/ts/client/tileUtils.ts +++ b/src/ts/common/tileUtils.ts @@ -1,17 +1,18 @@ import { PaletteManager, Season, TileSets, Region, TileType, Camera, PaletteSpriteBatch, DrawOptions, WorldMap, IMap, - Sprite, MapType -} from '../common/interfaces'; + Sprite, MapType, + canWalk +} from './interfaces'; import * as sprites from '../generated/sprites'; -import { getRegionTile, getRegionElevation } from '../common/region'; -import { getRegionGlobal } from '../common/worldMap'; -import { tileWidth, tileHeight, tileElevation, WATER_FPS, REGION_SIZE, WATER_HEIGHT } from '../common/constants'; -import { clamp, toInt, at, invalidEnumReturn } from '../common/utils'; -import { isAreaVisible } from '../common/camera'; -import { WHITE } from '../common/colors'; +import { getRegionTile, getRegionElevation, setRegionTile, getRegionTileIndex, setRegionTileDirty, doRelativeToRegion, getRegionGlobal } from './region'; +import { tileWidth, tileHeight, tileElevation, WATER_FPS, REGION_SIZE, WATER_HEIGHT } from './constants'; +import { clamp, toInt, at, invalidEnumReturn } from './utils'; +import { isAreaVisible } from './camera'; +import { WHITE } from './colors'; import { releasePalette } from '../graphics/paletteManager'; import { drawPixelText } from '../graphics/graphicsUtils'; -import { toScreenX, toScreenY, toWorldZ } from '../common/positionUtils'; +import { toScreenX, toScreenY, toWorldZ } from './positionUtils'; +import { setColliderDirty } from './collision'; const TILE_COUNTS = [[0, 4], [2, 3], [4, 3], [6, 3], [8, 3], [13, 3], [14, 3], [47, 4]]; export const TILE_COUNT_MAP: number[] = []; @@ -600,3 +601,51 @@ export function getTileHeight( return 0; } + +export function getTile(map: IMap, x: number, y: number): TileType { + const region = getRegionGlobal(map, x, y) as any as Region; + + if (region) { + const regionX = Math.floor(x - region.x * REGION_SIZE); + const regionY = Math.floor(y - region.y * REGION_SIZE); + return getRegionTile(region, regionX, regionY); + } else { + return TileType.None; + } +} + +export function setTile(map: WorldMap, worldX: number, worldY: number, type: TileType) { + const region = getRegionGlobal(map, worldX, worldY); + + if (!region) + return; + + const x = Math.floor(worldX - region.x * REGION_SIZE); + const y = Math.floor(worldY - region.y * REGION_SIZE); + + const old = getRegionTile(region, x, y); + setRegionTile(region, x, y, type); + + setTilesDirty(map, worldX - 1, worldY - 1, 3, 3); + + if (canWalk(old) !== canWalk(type)) { + setColliderDirty(map, region, x, y); + } +} + +export function setTilesDirty(map: IMap, ox: number, oy: number, w: number, h: number) { + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + doRelativeToRegion(map, x + ox, y + oy, (region, x, y) => setRegionTileDirty(region, x, y)); + } + } +} + +export function getTileIndex2(map: IMap, x: number, y: number) { + const region = getRegionGlobal(map, x, y); + return region ? getRegionTileIndex(region, x - region.x * REGION_SIZE, y - region.y * REGION_SIZE) : 0; +} + +export function isInWaterAt(map: IMap, x: number, y: number) { + return getTile(map, x, y) === TileType.Water && isInWater(getTileIndex2(map, x, y), x, y); +} diff --git a/src/ts/client/timing.ts b/src/ts/common/timing.ts similarity index 100% rename from src/ts/client/timing.ts rename to src/ts/common/timing.ts diff --git a/src/ts/components/admin/admin-account-details/admin-account-details.ts b/src/ts/components/admin/admin-account-details/admin-account-details.ts index 02ff835..7a9ff90 100644 --- a/src/ts/components/admin/admin-account-details/admin-account-details.ts +++ b/src/ts/components/admin/admin-account-details/admin-account-details.ts @@ -5,7 +5,7 @@ import { Account, Event, Auth, ROLES, Character, MergeInfo, MergeAccountData, SupporterInvite, accountFlags, OriginInfoBase, DuplicateResult, AroundEntry, LogEntry } from '../../../common/adminInterfaces'; -import { compareByName, createSupporterChanges, SupporterChange, getTranslationUrl, getAge } from '../../../common/adminUtils'; +import { compareByName, SupporterChange, getTranslationUrl, getAge } from '../../../common/adminUtils'; import { hasRole } from '../../../common/accountUtils'; import { AdminModel } from '../../services/adminModel'; import { @@ -16,6 +16,7 @@ import { import { flagsToString, includes, flatten, removeItem } from '../../../common/utils'; import { Subscription } from '../../../common/interfaces'; import { showTextInNewTab } from '../../../client/htmlUtils'; +import { createSupporterChanges } from '../../../client/adminHtmlUtils'; const defaultLimit = 15; const defaultDuplicatesLimit = 10; diff --git a/src/ts/components/admin/shared/admin-chat-log/admin-chat-log.ts b/src/ts/components/admin/shared/admin-chat-log/admin-chat-log.ts index 5e179bd..018cbb6 100644 --- a/src/ts/components/admin/shared/admin-chat-log/admin-chat-log.ts +++ b/src/ts/components/admin/shared/admin-chat-log/admin-chat-log.ts @@ -2,10 +2,11 @@ import { Component, Input, OnDestroy, ElementRef } from '@angular/core'; import * as moment from 'moment'; import { AdminModel } from '../../../services/adminModel'; import { Account } from '../../../../common/adminInterfaces'; -import { ChatDate, createChatDate, createDateRange, replaceSwears } from '../../../../common/adminUtils'; +import { ChatDate, createChatDate, createDateRange } from '../../../../common/adminUtils'; import { faSearch, faSpinner, faSync, faFileAlt, faTimes, faChevronLeft, faChevronRight } from '../../../../client/icons'; import { removeAllNodes, appendAllNodes, showTextInNewTab } from '../../../../client/htmlUtils'; import { includes } from '../../../../common/utils'; +import { replaceSwears } from '../../../../client/adminHtmlUtils'; @Component({ selector: 'admin-chat-log', diff --git a/src/ts/components/app/about/about.ts b/src/ts/components/app/about/about.ts index 039a931..e549818 100644 --- a/src/ts/components/app/about/about.ts +++ b/src/ts/components/app/about/about.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { emojis } from '../../../client/emoji'; +import { emojis } from '../../../common/emoji'; import { getUrl } from '../../../client/rev'; import { CREDITS, CONTRIBUTORS, Credit } from '../../../client/credits'; import { CHANGELOG } from '../../../generated/changelog'; diff --git a/src/ts/components/app/account/account.ts b/src/ts/components/app/account/account.ts index d885634..d5f53ea 100644 --- a/src/ts/components/app/account/account.ts +++ b/src/ts/components/app/account/account.ts @@ -2,13 +2,14 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { ACCOUNT_NAME_MAX_LENGTH, ACCOUNT_NAME_MIN_LENGTH, HIDES_PER_PAGE } from '../../../common/constants'; import { UpdateAccountData, SocialSiteInfo, OAuthProvider, HiddenPlayer } from '../../../common/interfaces'; import { - toSocialSiteInfo, cleanName, supporterTitle, supporterClass, isSupporterOrPastSupporter, supporterRewards + toSocialSiteInfo, supporterTitle, supporterClass, isSupporterOrPastSupporter, supporterRewards } from '../../../client/clientUtils'; import { oauthProviders } from '../../../client/data'; import { Model } from '../../services/model'; import { getProviderIcon } from '../../shared/sign-in-box/sign-in-box'; import { faStar, faExclamationCircle, faSync } from '../../../client/icons'; import { Router } from '@angular/router'; +import { cleanName } from '../../../common/stringUtils'; @Component({ selector: 'account', diff --git a/src/ts/components/app/app.ts b/src/ts/components/app/app.ts index 5346583..01a46aa 100644 --- a/src/ts/components/app/app.ts +++ b/src/ts/components/app/app.ts @@ -15,9 +15,9 @@ import { ErrorReporter } from '../services/errorReporter'; import { SECOND, PONY_TYPE } from '../../common/constants'; import { ChatBox } from '../shared/chat-box/chat-box'; import { ChatLogMessage } from '../shared/chat-log/chat-log'; -import { isPony } from '../../common/pony'; -import { findEntityById } from '../../common/worldMap'; +import { findEntityById } from '../../client/worldMap'; import { isSelected } from '../../client/gameUtils'; +import { isPony } from '../../common/entityUtils'; export function tooltipConfig() { return Object.assign(new TooltipConfig(), { container: 'body' }); diff --git a/src/ts/components/app/character/character.ts b/src/ts/components/app/character/character.ts index 2b88abd..e2c0fd8 100644 --- a/src/ts/components/app/character/character.ts +++ b/src/ts/components/app/character/character.ts @@ -9,18 +9,18 @@ import { findById, toInt, cloneDeep, delay } from '../../../common/utils'; import { SLEEVED_ACCESSORIES, frontHooves, mergedBackManes, mergedManes, mergedFacialHair, mergedEarAccessories, mergedChestAccessories, mergedFaceAccessories, mergedBackAccessories, mergedExtraAccessories, mergedHeadAccessories -} from '../../../client/ponyUtils'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../../client/ponyHelpers'; +} from '../../../common/ponyUtils'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../../common/ponyHelpers'; import { toPalette, getBaseFill, syncLockedPonyInfo } from '../../../common/ponyInfo'; import * as sprites from '../../../generated/sprites'; -import { boop, trot, stand, sitDownUp, lieDownUp, fly, flyBug } from '../../../client/ponyAnimations'; +import { boop, trot, stand, sitDownUp, lieDownUp, fly, flyBug } from '../../../common/ponyAnimations'; import { drawCanvas } from '../../../graphics/contextSpriteBatch'; import { Model, getPonyTag } from '../../services/model'; -import { loadAndInitSpriteSheets, addTitles, createEyeSprite, addLabels } from '../../../client/spriteUtils'; +import { addTitles, createEyeSprite, addLabels } from '../../../common/spriteUtils'; import { GameService } from '../../services/gameService'; import { TRANSPARENT, BLACK, blushColor } from '../../../common/colors'; import { precompressPony, compressPonyString, decompressPony, decompressPonyString } from '../../../common/compressPony'; -import { saveCanvas } from '../../../client/canvasUtils'; +import { saveCanvas } from '../../../common/canvasUtils'; import { drawPony } from '../../../client/ponyDraw'; import { getProviderIcon } from '../../shared/sign-in-box/sign-in-box'; import { faPlay, faLock, faSave, faCode, faInfoCircle } from '../../../client/icons'; @@ -28,6 +28,7 @@ import { isFileSaverSupported, createExpression, readFileAsText } from '../../.. import { emptyTag, getAvailableTags } from '../../../common/tags'; import { ButtMarkEditorState } from '../../shared/butt-mark-editor/butt-mark-editor'; import { parseColorWithAlpha } from '../../../common/color'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const frontHoofTitles = ['', 'Fetlocks', 'Paws', 'Claws', '']; const backHoofTitles = ['', 'Fetlocks', 'Paws', '', '']; diff --git a/src/ts/components/app/help/help.ts b/src/ts/components/app/help/help.ts index 7d14a79..80bdcec 100644 --- a/src/ts/components/app/help/help.ts +++ b/src/ts/components/app/help/help.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { emojis } from '../../../client/emoji'; +import { emojis } from '../../../common/emoji'; import { faArrowLeft, faArrowRight, faArrowUp, faArrowDown } from '../../../client/icons'; import { contactEmail, contactDiscord } from '../../../client/data'; import { ActivatedRoute } from '@angular/router'; diff --git a/src/ts/components/app/home/home.ts b/src/ts/components/app/home/home.ts index e35eb02..aa4e333 100644 --- a/src/ts/components/app/home/home.ts +++ b/src/ts/components/app/home/home.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; import { Model, getPonyTag } from '../../services/model'; -import { defaultPonyState } from '../../../client/ponyHelpers'; +import { defaultPonyState } from '../../../common/ponyHelpers'; import { GameService } from '../../services/gameService'; import { OAuthProvider, PonyObject } from '../../../common/interfaces'; -import { stand } from '../../../client/ponyAnimations'; +import { stand } from '../../../common/ponyAnimations'; @Component({ selector: 'home', diff --git a/src/ts/components/services/adminModel.ts b/src/ts/components/services/adminModel.ts index fbcc0d2..c27643f 100644 --- a/src/ts/components/services/adminModel.ts +++ b/src/ts/components/services/adminModel.ts @@ -15,11 +15,12 @@ import { LiveCollection } from './liveCollection'; import { socketOptions, token } from '../../client/data'; import { getUrl } from '../../client/rev'; import { - formatChat, formatEventDesc, getId, banMessage, parsePonies + getId, banMessage, parsePonies } from '../../common/adminUtils'; import { StorageService } from './storageService'; import { decompressPonyString } from '../../common/compressPony'; import { ModelSubscriber } from './modelSubscriber'; +import { formatChat, formatEventDesc } from '../../client/adminHtmlUtils'; interface FindPoniesResult { items: string[]; diff --git a/src/ts/components/services/model.ts b/src/ts/components/services/model.ts index f1d72b4..00649af 100644 --- a/src/ts/components/services/model.ts +++ b/src/ts/components/services/model.ts @@ -16,10 +16,10 @@ import { } from '../../common/errors'; import { version, host } from '../../client/data'; import { - toSocialSiteInfo, cleanName, validatePonyName, isStandalone, attachDebugMethod + toSocialSiteInfo, isStandalone, attachDebugMethod } from '../../client/clientUtils'; import { ErrorReporter } from './errorReporter'; -import { randomString } from '../../common/stringUtils'; +import { cleanName, randomString, validatePonyName } from '../../common/stringUtils'; import { StorageService } from './storageService'; import { decompressPonyString, compressPonyString, decodePonyInfo } from '../../common/compressPony'; import { SECOND, PLAYER_DESC_MAX_LENGTH, NEW_ACCOUNT_PONY_NAME } from '../../common/constants'; diff --git a/src/ts/components/shared/actions-modal/actions-modal.ts b/src/ts/components/shared/actions-modal/actions-modal.ts index 209f234..dafb326 100644 --- a/src/ts/components/shared/actions-modal/actions-modal.ts +++ b/src/ts/components/shared/actions-modal/actions-modal.ts @@ -12,7 +12,7 @@ import { import { createExpression, readFileAsText } from '../../../client/clientUtils'; import { ACTION_EXPRESSION_BG, ACTION_EXPRESSION_EYE_COLOR, fillToOutline } from '../../../common/colors'; import { faLock, faApple, faLaughBeam, faComment, faCog, faCogs } from '../../../client/icons'; -import { createEyeSprite } from '../../../client/spriteUtils'; +import { createEyeSprite } from '../../../common/spriteUtils'; import { times, hasFlag } from '../../../common/utils'; import { PonyTownGame } from '../../../client/game'; import { getEntityNames } from '../../services/model'; diff --git a/src/ts/components/shared/character-preview/character-preview.ts b/src/ts/components/shared/character-preview/character-preview.ts index 42f8e6d..2e173d6 100644 --- a/src/ts/components/shared/character-preview/character-preview.ts +++ b/src/ts/components/shared/character-preview/character-preview.ts @@ -6,16 +6,16 @@ import { toPalette } from '../../../common/ponyInfo'; import { GRASS_COLOR, TRANSPARENT } from '../../../common/colors'; import { createCanvas, disableImageSmoothing, getPixelRatio, resizeCanvas, resizeCanvasWithRatio -} from '../../../client/canvasUtils'; -import { BLINK_FRAMES } from '../../../client/ponyUtils'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../../client/ponyHelpers'; +} from '../../../common/canvasUtils'; +import { BLINK_FRAMES } from '../../../common/ponyUtils'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../../common/ponyHelpers'; import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; import { colorToCSS } from '../../../common/color'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { drawNamePlate, commonPalettes, DrawNameFlags } from '../../../graphics/graphicsUtils'; import { drawPony } from '../../../client/ponyDraw'; import { paletteSpriteSheet } from '../../../generated/sprites'; -import { replaceEmojis } from '../../../client/emoji'; +import { replaceEmojis } from '../../../common/emoji'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const DEFAULT_STATE = defaultPonyState(); const DEFAULT_OPTIONS = defaultDrawPonyOptions(); diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index b3a77c8..e9de392 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -4,16 +4,17 @@ import { ChatType, isPartyChat, Entity, FakeEntity } from '../../../common/inter import { SAY_MAX_LENGTH } from '../../../common/constants'; import { Key } from '../../../client/input/input'; import { PonyTownGame } from '../../../client/game'; -import { cleanMessage, isSpamMessage } from '../../../client/clientUtils'; +import { isSpamMessage } from '../../../client/clientUtils'; import { faComment, faAngleDoubleRight } from '../../../client/icons'; import { isInParty } from '../../../client/partyUtils'; import { handleActionCommand } from '../../../client/playerActions'; -import { hasHeadAnimation } from '../../../common/pony'; -import { AutocompleteState, autocompleteMesssage, replaceEmojis, emojis } from '../../../client/emoji'; +import { hasHeadAnimation } from '../../../client/pony'; +import { AutocompleteState, autocompleteMesssage, replaceEmojis, emojis } from '../../../common/emoji'; import { replaceNodes } from '../../../client/htmlUtils'; import { invalidEnumReturn } from '../../../common/utils'; import { findMatchingEntityNames, findEntityOrMockByAnyMeans, findBestEntityByName } from '../../../client/handlers'; import { sample } from 'lodash'; +import { cleanMessage } from '../../../common/stringUtils'; const chatTypeNames: string[] = []; const chatTypeClasses: string[] = []; diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 9993474..87902f4 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -11,7 +11,7 @@ import { element, textNode, removeAllNodes, replaceNodes } from '../../../client import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE, SECOND } from '../../../common/constants'; import { faCaretUp, faArrowDown, faSearch } from '../../../client/icons'; import { sampleMessages } from '../../../common/debugData'; -import { findEntityById } from '../../../common/worldMap'; +import { findEntityById } from '../../../client/worldMap'; import { colorToRGBA, rgb2hsl, HSL, hsl2CSS } from '../../../common/color'; import * as moment from 'moment'; import { isMobile } from '../../../client/data'; diff --git a/src/ts/components/shared/discord-pony/discord-pony.ts b/src/ts/components/shared/discord-pony/discord-pony.ts index 4191180..4cc189a 100644 --- a/src/ts/components/shared/discord-pony/discord-pony.ts +++ b/src/ts/components/shared/discord-pony/discord-pony.ts @@ -1,9 +1,9 @@ import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core'; -import { defaultExpression } from '../../../client/ponyUtils'; -import { defaultPonyState } from '../../../client/ponyHelpers'; +import { defaultExpression } from '../../../common/ponyUtils'; +import { defaultPonyState } from '../../../common/ponyHelpers'; import { DISCORD_PONY } from '../../../common/constants'; import { Expression, Muzzle, HeadAnimation, Iris } from '../../../common/interfaces'; -import { excite } from '../../../client/ponyAnimations'; +import { excite } from '../../../common/ponyAnimations'; import { FrameService, FrameLoop } from '../../services/frameService'; import { CharacterPreview } from '../character-preview/character-preview'; import { decompressPonyString } from '../../../common/compressPony'; diff --git a/src/ts/components/shared/emote-box/emote-box.ts b/src/ts/components/shared/emote-box/emote-box.ts index cf9cbe9..d4f2b5a 100644 --- a/src/ts/components/shared/emote-box/emote-box.ts +++ b/src/ts/components/shared/emote-box/emote-box.ts @@ -1,8 +1,8 @@ import { Component, Input, AfterViewInit, ElementRef, ChangeDetectionStrategy, ViewChild, NgZone } from '@angular/core'; -import { findEmoji, getEmojiImageAsync } from '../../../client/emoji'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; -import { font } from '../../../client/fonts'; +import { findEmoji, getEmojiImageAsync } from '../../../common/emoji'; +import { font } from '../../../common/fonts'; import { getCharacterSprite } from '../../../graphics/spriteFont'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; @Component({ selector: 'emote-box', diff --git a/src/ts/components/shared/notification/notification-item.ts b/src/ts/components/shared/notification/notification-item.ts index af9cf95..7a48b0d 100644 --- a/src/ts/components/shared/notification/notification-item.ts +++ b/src/ts/components/shared/notification/notification-item.ts @@ -3,7 +3,7 @@ import { PlayerAction, Notification, NotificationFlags, EntityPlayerState } from import { PonyTownGame } from '../../../client/game'; import { hasFlag, setFlag } from '../../../common/utils'; import { faBan } from '../../../client/icons'; -import { getPaletteInfo } from '../../../common/pony'; +import { getPaletteInfo } from '../../../client/pony'; @Component({ selector: 'notification-item', diff --git a/src/ts/components/shared/party-box/party-box.ts b/src/ts/components/shared/party-box/party-box.ts index eb73ea6..caee9b9 100644 --- a/src/ts/components/shared/party-box/party-box.ts +++ b/src/ts/components/shared/party-box/party-box.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { PartyMember } from '../../../common/interfaces'; import { PonyTownGame } from '../../../client/game'; import { partyLeaderIcon, offlineIcon } from '../../../client/icons'; -import { getPaletteInfo } from '../../../common/pony'; +import { getPaletteInfo } from '../../../client/pony'; @Component({ selector: 'party-box', diff --git a/src/ts/components/shared/play-box/play-box.ts b/src/ts/components/shared/play-box/play-box.ts index 87796a3..45cd5a6 100644 --- a/src/ts/components/shared/play-box/play-box.ts +++ b/src/ts/components/shared/play-box/play-box.ts @@ -10,10 +10,10 @@ import { GameService } from '../../services/gameService'; import { Model } from '../../services/model'; import { faSpinner, faExclamationCircle, faInfoCircle, faGlobe, faStar, faWrench } from '../../../client/icons'; import { isBrowserOutdated, hardReload, isAndroidBrowser } from '../../../client/clientUtils'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { StorageService } from '../../services/storageService'; import { ErrorReporter } from '../../services/errorReporter'; import { REQUEST_DATE_OF_BIRTH } from '../../../common/constants'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const ignoredErrors = [ WEBGL_CREATION_ERROR, diff --git a/src/ts/components/shared/pony-box/pony-box.ts b/src/ts/components/shared/pony-box/pony-box.ts index 87a17f6..fe32fc2 100644 --- a/src/ts/components/shared/pony-box/pony-box.ts +++ b/src/ts/components/shared/pony-box/pony-box.ts @@ -1,6 +1,6 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; import { PlayerAction, Pony, EntityPlayerState, Entity } from '../../../common/interfaces'; -import { getPaletteInfo } from '../../../common/pony'; +import { getPaletteInfo } from '../../../client/pony'; import { Model } from '../../services/model'; import { PonyTownGame } from '../../../client/game'; import { diff --git a/src/ts/components/shared/portrait-box/portrait-box.ts b/src/ts/components/shared/portrait-box/portrait-box.ts index 327ba81..e004ae1 100644 --- a/src/ts/components/shared/portrait-box/portrait-box.ts +++ b/src/ts/components/shared/portrait-box/portrait-box.ts @@ -3,11 +3,11 @@ import { } from '@angular/core'; import { PalettePonyInfo } from '../../../common/interfaces'; import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; -import { createCanvas, disableImageSmoothing, getPixelRatio, resizeCanvasWithRatio } from '../../../client/canvasUtils'; -import { defaultDrawPonyOptions, defaultPonyState } from '../../../client/ponyHelpers'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; +import { createCanvas, disableImageSmoothing, getPixelRatio, resizeCanvasWithRatio } from '../../../common/canvasUtils'; +import { defaultDrawPonyOptions, defaultPonyState } from '../../../common/ponyHelpers'; import { drawPony } from '../../../client/ponyDraw'; import { paletteSpriteSheet } from '../../../generated/sprites'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const scales: { [key: string]: number } = { large: 3, diff --git a/src/ts/components/shared/set-selection/set-selection.ts b/src/ts/components/shared/set-selection/set-selection.ts index 1906a0e..f776252 100644 --- a/src/ts/components/shared/set-selection/set-selection.ts +++ b/src/ts/components/shared/set-selection/set-selection.ts @@ -1,7 +1,7 @@ import { Component, Input, Output, EventEmitter, OnChanges, Directive, Optional } from '@angular/core'; import { clamp } from 'lodash'; import { SpriteSet, ColorExtraSets, ColorExtraSet } from '../../../common/interfaces'; -import { getColorCount } from '../../../client/spriteUtils'; +import { getColorCount } from '../../../common/spriteUtils'; const FILLS = ['Orange', 'DodgerBlue', 'LimeGreen', 'Orchid', 'crimson', 'Aquamarine']; const OUTLINES = ['Chocolate', 'SteelBlue', 'ForestGreen', 'DarkOrchid', 'darkred', 'DarkTurquoise']; diff --git a/src/ts/components/shared/sprite-box/sprite-box.ts b/src/ts/components/shared/sprite-box/sprite-box.ts index 124c188..edbd004 100644 --- a/src/ts/components/shared/sprite-box/sprite-box.ts +++ b/src/ts/components/shared/sprite-box/sprite-box.ts @@ -5,12 +5,12 @@ import { Rect, Sprite, ColorExtra, Palette } from '../../../common/interfaces'; import { parseColor, colorToCSS } from '../../../common/color'; import { mockPaletteManager, toColorList, getColorsFromSet } from '../../../common/ponyInfo'; import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; -import { createCanvas, disableImageSmoothing, resizeCanvas } from '../../../client/canvasUtils'; +import { createCanvas, disableImageSmoothing, resizeCanvas } from '../../../common/canvasUtils'; import { WHITE } from '../../../common/colors'; import { rect } from '../../../common/rect'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { faTimes } from '../../../client/icons'; import { paletteSpriteSheet } from '../../../generated/sprites'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; let redrawFrame = 0; const forRedraw: SpriteBox[] = []; diff --git a/src/ts/components/shared/visit-pt-pony/visit-pt-pony.ts b/src/ts/components/shared/visit-pt-pony/visit-pt-pony.ts index c863fd6..a1976ec 100644 --- a/src/ts/components/shared/visit-pt-pony/visit-pt-pony.ts +++ b/src/ts/components/shared/visit-pt-pony/visit-pt-pony.ts @@ -1,8 +1,8 @@ import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core'; -import { defaultExpression } from '../../../client/ponyUtils'; -import { defaultPonyState } from '../../../client/ponyHelpers'; +import { defaultExpression } from '../../../common/ponyUtils'; +import { defaultPonyState } from '../../../common/ponyHelpers'; import { Expression, Muzzle, HeadAnimation, BodyAnimation, Eye } from '../../../common/interfaces'; -import { excite_meno, happy_tongue_meno, stand, boop, happy_tongue_meno_2 } from '../../../client/ponyAnimations'; +import { excite_meno, happy_tongue_meno, stand, boop, happy_tongue_meno_2 } from '../../../common/ponyAnimations'; import { FrameService, FrameLoop } from '../../services/frameService'; import { CharacterPreview } from '../character-preview/character-preview'; import { decompressPonyString } from '../../../common/compressPony'; diff --git a/src/ts/components/tools/sheetExport.ts b/src/ts/components/tools/sheetExport.ts index 563a5ed..9e6588a 100644 --- a/src/ts/components/tools/sheetExport.ts +++ b/src/ts/components/tools/sheetExport.ts @@ -4,9 +4,9 @@ import { Psd, writePsd, Layer } from 'ag-psd'; import { SpriteSet, PonyInfoNumber, PaletteSpriteSet, NoDraw } from '../../common/interfaces'; import { times, cloneDeep, setFlag, includes, toInt } from '../../common/utils'; import { createDefaultPony, syncLockedPonyInfoNumber, toPaletteNumber, mockPaletteManager } from '../../common/ponyInfo'; -import { Sets } from '../../client/ponyUtils'; -import { defaultDrawPonyOptions, defaultPonyState } from '../../client/ponyHelpers'; -import { createCanvas, disableImageSmoothing } from '../../client/canvasUtils'; +import { Sets } from '../../common/ponyUtils'; +import { defaultDrawPonyOptions, defaultPonyState } from '../../common/ponyHelpers'; +import { createCanvas, disableImageSmoothing } from '../../common/canvasUtils'; import { ContextSpriteBatch } from '../../graphics/contextSpriteBatch'; import { BLACK, BLUE, CYAN, WHITE, RED, GREEN, YELLOW, MAGENTA, TRANSPARENT } from '../../common/colors'; import { colorToCSS } from '../../common/color'; @@ -15,7 +15,7 @@ import { drawPony } from '../../client/ponyDraw'; import * as sprites from '../../generated/sprites'; import { drawPixelTextOnCanvas, fillRect } from '../../graphics/graphicsUtils'; import { Sheet, SheetLayer, ignoreSet, DEFAULT_COLOR } from '../../common/sheets'; -import { createHeadAnimation } from '../../client/ponyAnimations'; +import { createHeadAnimation } from '../../common/ponyAnimations'; const PONY_X = 30; const PONY_Y = 50; diff --git a/src/ts/components/tools/tools-animation/tools-animation.ts b/src/ts/components/tools/tools-animation/tools-animation.ts index 801e7ea..f1fdff1 100644 --- a/src/ts/components/tools/tools-animation/tools-animation.ts +++ b/src/ts/components/tools/tools-animation/tools-animation.ts @@ -12,15 +12,15 @@ import { import { removeItem, repeat, isKeyEventInvalid, cloneDeep, array, hasFlag } from '../../../common/utils'; import { toPalette, createDefaultPony, syncLockedPonyInfo } from '../../../common/ponyInfo'; import { Key } from '../../../client/input/input'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../../client/ponyHelpers'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../../common/ponyHelpers'; import { headAnimations, animations, createBodyFrame, createHeadFrame, stand, sit, mergeAnimations, sitDown, lieDown, lie, sitUp, standUp -} from '../../../client/ponyAnimations'; +} from '../../../common/ponyAnimations'; import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; import * as sprites from '../../../generated/sprites'; -import { createCanvas, disableImageSmoothing, saveCanvas } from '../../../client/canvasUtils'; -import { loadAndInitSpriteSheets, createEyeSprite } from '../../../client/spriteUtils'; +import { createCanvas, disableImageSmoothing, saveCanvas } from '../../../common/canvasUtils'; +import { createEyeSprite } from '../../../common/spriteUtils'; import { drawPony } from '../../../client/ponyDraw'; import { faLock, faHome, faArrowRight, faArrowLeft, faPause, faPlay, faChevronRight, faChevronLeft, faRetweet, @@ -30,6 +30,7 @@ import { import { FrameService, FrameLoop } from '../../services/frameService'; import { StorageService } from '../../services/storageService'; import { decompressPonyString } from '../../../common/compressPony'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const ponyWidth = 80; const ponyHeight = 80; diff --git a/src/ts/components/tools/tools-chat/tools-chat.ts b/src/ts/components/tools/tools-chat/tools-chat.ts index 3929340..0f746a8 100644 --- a/src/ts/components/tools/tools-chat/tools-chat.ts +++ b/src/ts/components/tools/tools-chat/tools-chat.ts @@ -7,16 +7,16 @@ import { GRASS_COLOR, getMessageColor, OUTLINE_COLOR, MOD_COLOR, ADMIN_COLOR, PATREON_COLOR, ANNOUNCEMENT_COLOR, WHITE, PARTY_COLOR, RED, ORANGE, PURPLE, GREEN, YELLOW, BLUE, BLACK, CYAN, TRANSPARENT, WHISPER_COLOR } from '../../../common/colors'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { MessageType, FontPalettes, Palette } from '../../../common/interfaces'; import { faHome, faStar } from '../../../client/icons'; import * as sprites from '../../../generated/sprites'; -import { disableImageSmoothing } from '../../../client/canvasUtils'; +import { disableImageSmoothing } from '../../../common/canvasUtils'; import { mockPaletteManager } from '../../../common/ponyInfo'; -import { fontPal, fontSmallPal } from '../../../client/fonts'; +import { fontPal, fontSmallPal } from '../../../common/fonts'; import { measureText, drawText, drawOutlinedText, lineBreak, drawTextAligned, HAlign } from '../../../graphics/spriteFont'; import { rect } from '../../../common/rect'; import { colorToCSS } from '../../../common/color'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; interface Message { label: string; diff --git a/src/ts/components/tools/tools-collisions/tools-collisions.ts b/src/ts/components/tools/tools-collisions/tools-collisions.ts index 8abcd64..d26e936 100644 --- a/src/ts/components/tools/tools-collisions/tools-collisions.ts +++ b/src/ts/components/tools/tools-collisions/tools-collisions.ts @@ -3,7 +3,7 @@ import { AgDragEvent } from '../../shared/directives/agDrag'; import { Rect, Point } from '../../../common/interfaces'; import { roundPosition } from '../../../common/positionUtils'; import { point, distanceSquaredXY, clamp } from '../../../common/utils'; -import { createCanvas, disableImageSmoothing } from '../../../client/canvasUtils'; +import { createCanvas, disableImageSmoothing } from '../../../common/canvasUtils'; const pixelSize = 10; const tileWidth = 32 * pixelSize; diff --git a/src/ts/components/tools/tools-entity/tools-entity.ts b/src/ts/components/tools/tools-entity/tools-entity.ts index 8cd6708..692bbbc 100644 --- a/src/ts/components/tools/tools-entity/tools-entity.ts +++ b/src/ts/components/tools/tools-entity/tools-entity.ts @@ -10,18 +10,18 @@ import { SHADOW_COLOR, WHITE, BLACK, TRANSPARENT, RED, ORANGE, PURPLE } from '.. import { Key } from '../../../client/input/input'; import { drawOutline } from '../../../graphics/graphicsUtils'; import { drawCanvas, ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { AgDragEvent } from '../../shared/directives/agDrag'; import { faHome, faSave, faEraser, faTrash, faPlus, faCrosshairs } from '../../../client/icons'; import { StorageService } from '../../services/storageService'; import { mockPaletteManager, toPalette } from '../../../common/ponyInfo'; import { OFFLINE_PONY } from '../../../common/constants'; import { drawPony } from '../../../client/ponyDraw'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../../client/ponyHelpers'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../../common/ponyHelpers'; import { createBaseEntity } from '../../../common/entities'; import { decompressPonyString } from '../../../common/compressPony'; -import { disableImageSmoothing } from '../../../client/canvasUtils'; +import { disableImageSmoothing } from '../../../common/canvasUtils'; import { toScreenX, toScreenYWithZ } from '../../../common/positionUtils'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const COVER = parseColor('DeepSkyBlue'); const COLLIDER = ORANGE; diff --git a/src/ts/components/tools/tools-expressions/tools-expressions.ts b/src/ts/components/tools/tools-expressions/tools-expressions.ts index abd6a7e..a1a48d2 100644 --- a/src/ts/components/tools/tools-expressions/tools-expressions.ts +++ b/src/ts/components/tools/tools-expressions/tools-expressions.ts @@ -1,16 +1,16 @@ import { Component, OnInit, ElementRef, ViewChild } from '@angular/core'; import { PonyInfo, PonyState } from '../../../common/interfaces'; import { toPalette, createDefaultPony, syncLockedPonyInfo } from '../../../common/ponyInfo'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../../client/ponyHelpers'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../../common/ponyHelpers'; import { expressions } from '../../../common/expressions'; -import { createCanvas, disableImageSmoothing, saveCanvas } from '../../../client/canvasUtils'; +import { createCanvas, disableImageSmoothing, saveCanvas } from '../../../common/canvasUtils'; import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; import { RED } from '../../../common/colors'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; -import { createBodyAnimation } from '../../../client/ponyAnimations'; +import { createBodyAnimation } from '../../../common/ponyAnimations'; import { drawPony } from '../../../client/ponyDraw'; import { faHome } from '../../../client/icons'; import { paletteSpriteSheet } from '../../../generated/sprites'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; @Component({ selector: 'tools-expressions', diff --git a/src/ts/components/tools/tools-map/tools-map.ts b/src/ts/components/tools/tools-map/tools-map.ts index 01f45bd..c96f488 100644 --- a/src/ts/components/tools/tools-map/tools-map.ts +++ b/src/ts/components/tools/tools-map/tools-map.ts @@ -1,10 +1,9 @@ import { Component, OnInit, ElementRef, ViewChild } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { saveCanvas, disableImageSmoothing, createCanvas } from '../../../client/canvasUtils'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; +import { saveCanvas, disableImageSmoothing, createCanvas } from '../../../common/canvasUtils'; import { tileHeight, tileWidth, REGION_SIZE } from '../../../common/constants'; import { faHome } from '../../../client/icons'; -import { updateMap, getTile, createWorldMap, setRegion, setTile } from '../../../common/worldMap'; +import { updateMap, createWorldMap, setRegion } from '../../../client/worldMap'; import { Season, DrawOptions, defaultDrawOptions, EntityFlags, Entity, WorldMap, MapType, MapFlags } from '../../../common/interfaces'; @@ -12,7 +11,7 @@ import { drawCanvas } from '../../../graphics/contextSpriteBatch'; import { paletteSpriteSheet } from '../../../generated/sprites'; import { createRegion } from '../../../common/region'; import { deserializeTiles } from '../../../common/compress'; -import { createTileSets } from '../../../client/tileUtils'; +import { createTileSets, getTile, setTile } from '../../../common/tileUtils'; import { createCamera } from '../../../common/camera'; import { mockPaletteManager } from '../../../common/ponyInfo'; import { isCritter } from '../../../common/entityUtils'; @@ -25,6 +24,7 @@ import { getShadowColor, HOUR_LENGTH, createLightData } from '../../../common/ti import { StorageService } from '../../services/storageService'; import { getTileColor } from '../../../common/colors'; import { colorToCSS } from '../../../common/color'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; export interface ToolsMapOtherInfo { season: Season; diff --git a/src/ts/components/tools/tools-palette/tools-palette.ts b/src/ts/components/tools/tools-palette/tools-palette.ts index 26ea2c7..d137f93 100644 --- a/src/ts/components/tools/tools-palette/tools-palette.ts +++ b/src/ts/components/tools/tools-palette/tools-palette.ts @@ -4,11 +4,11 @@ import { setPaletteManager } from '../../../common/mixins'; import { parseColor, colorToCSS } from '../../../common/color'; import { PaletteManager, releasePalette } from '../../../graphics/paletteManager'; import { drawCanvas } from '../../../graphics/contextSpriteBatch'; -import { disableImageSmoothing } from '../../../client/canvasUtils'; +import { disableImageSmoothing } from '../../../common/canvasUtils'; import { SHADOW_COLOR, WHITE } from '../../../common/colors'; import { PaletteRenderable } from '../../../common/interfaces'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { faHome } from '../../../client/icons'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const BG = parseColor('lightgreen'); const DEFAULT_PALETTE = [0, 0xffffffff]; diff --git a/src/ts/components/tools/tools-sheet/tools-sheet.ts b/src/ts/components/tools/tools-sheet/tools-sheet.ts index 5414b4e..5af6f95 100644 --- a/src/ts/components/tools/tools-sheet/tools-sheet.ts +++ b/src/ts/components/tools/tools-sheet/tools-sheet.ts @@ -1,12 +1,12 @@ import { Component, OnInit, ElementRef, ViewChild } from '@angular/core'; import { compact } from 'lodash'; import { getCols, getRows, createPsd, savePsd, drawPsd } from '../sheetExport'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; -import { saveCanvas } from '../../../client/canvasUtils'; +import { saveCanvas } from '../../../common/canvasUtils'; import { faHome, faSync, faFileImage } from '../../../client/icons'; import { StorageService } from '../../services/storageService'; import { at } from '../../../common/utils'; import { sheets, Sheet } from '../../../common/sheets'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; @Component({ selector: 'tools-sheet', diff --git a/src/ts/components/tools/tools-states/tools-states.ts b/src/ts/components/tools/tools-states/tools-states.ts index c801e14..b8a1cf6 100644 --- a/src/ts/components/tools/tools-states/tools-states.ts +++ b/src/ts/components/tools/tools-states/tools-states.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { fromPairs } from 'lodash'; import { faHome } from '../../../client/icons'; -import { ponyStates, } from '../../../client/ponyStates'; +import { ponyStates, } from '../../../common/ponyStates'; import { AgDragEvent } from '../../shared/directives/agDrag'; import { AnimatorState } from '../../../common/animator'; import { distance, flatten } from '../../../common/utils'; diff --git a/src/ts/components/tools/tools-ui/tools-ui.ts b/src/ts/components/tools/tools-ui/tools-ui.ts index aa8ad51..4df7382 100644 --- a/src/ts/components/tools/tools-ui/tools-ui.ts +++ b/src/ts/components/tools/tools-ui/tools-ui.ts @@ -9,20 +9,20 @@ import { fromNow, setFlag, times } from '../../../common/utils'; import { ChatLog } from '../../shared/chat-log/chat-log'; import { randomString } from '../../../common/stringUtils'; import { MessageType, Entity, EntityPlayerState } from '../../../common/interfaces'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { SettingsService } from '../../services/settingsService'; import { faHome, faStar, faLock, faHeart } from '../../../client/icons'; import { decompressPonyString } from '../../../common/compressPony'; import { getAllTags } from '../../../common/tags'; import { Model } from '../../services/model'; import { isPartyLeader } from '../../../client/partyUtils'; -import { createPony } from '../../../common/pony'; +import { createPony } from '../../../client/pony'; import { serializeActions, deserializeActions } from '../../../client/buttonActions'; import { initializeToys } from '../../../client/ponyDraw'; import { ACTION_EXPRESSION_BG, updateActionColor } from '../../../common/colors'; import { parseColor, colorToCSS, colorNames } from '../../../common/color'; import { isHidden, isIgnored, isFriend } from '../../../common/entityUtils'; import { initFeatureFlags } from '../../../client/clientUtils'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; const offlinePonyInfo = decompressPonyString(OFFLINE_PONY, true); const offlinePonyPal = toPalette(offlinePonyInfo); diff --git a/src/ts/components/tools/tools-variants/tools-variants.ts b/src/ts/components/tools/tools-variants/tools-variants.ts index d554d0b..2d501bc 100644 --- a/src/ts/components/tools/tools-variants/tools-variants.ts +++ b/src/ts/components/tools/tools-variants/tools-variants.ts @@ -1,14 +1,14 @@ import { Component, OnInit, ElementRef, ViewChild } from '@angular/core'; import { PonyInfo, PonyState } from '../../../common/interfaces'; -import { createCanvas, disableImageSmoothing } from '../../../client/canvasUtils'; +import { createCanvas, disableImageSmoothing } from '../../../common/canvasUtils'; import { toPalette, createDefaultPony, syncLockedPonyInfo } from '../../../common/ponyInfo'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../../client/ponyHelpers'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../../common/ponyHelpers'; import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch'; -import { loadAndInitSpriteSheets } from '../../../client/spriteUtils'; import { compressPonyString, decompressPony } from '../../../common/compressPony'; import { drawPony } from '../../../client/ponyDraw'; import { faHome } from '../../../client/icons'; import { paletteSpriteSheet } from '../../../generated/sprites'; +import { loadAndInitSpriteSheets } from '../../../client/loadSprites'; @Component({ selector: 'tools-variants', diff --git a/src/ts/graphics/baseSpriteBatch.ts b/src/ts/graphics/baseSpriteBatch.ts index f22abcb..8b31e48 100644 --- a/src/ts/graphics/baseSpriteBatch.ts +++ b/src/ts/graphics/baseSpriteBatch.ts @@ -4,7 +4,7 @@ import { colorToFloat, colorToFloatAlpha } from '../common/color'; import { BaseStateBatch } from './baseStateBatch'; import { VAO, createVAO } from './webgl/glVao'; import { VAOAttributeDefinition, getVAOAttributesSize, createVAOAttributes } from './webgl/vaoAttributes'; -import { timeStart, timeEnd } from '../client/timing'; +import { timeStart, timeEnd } from '../common/timing'; import { isIdentity } from '../common/mat2d'; // const BATCH_BUFFER_SIZE = 2048; // 8kb diff --git a/src/ts/graphics/contextSpriteBatch.ts b/src/ts/graphics/contextSpriteBatch.ts index d5e7bd3..d55d1ac 100644 --- a/src/ts/graphics/contextSpriteBatch.ts +++ b/src/ts/graphics/contextSpriteBatch.ts @@ -1,5 +1,5 @@ import { PaletteSpriteBatch, Sprite, Palette, SpriteBatch, SpriteSheet, Matrix2D, Batch } from '../common/interfaces'; -import { createCanvas } from '../client/canvasUtils'; +import { createCanvas } from '../common/canvasUtils'; import { colorToRGBA, getR, getG, getB, getAlpha } from '../common/color'; import { BaseStateBatch } from './baseStateBatch'; import { commonPalettes } from './graphicsUtils'; diff --git a/src/ts/graphics/graphicsUtils.ts b/src/ts/graphics/graphicsUtils.ts index cb7f014..03b7b7b 100644 --- a/src/ts/graphics/graphicsUtils.ts +++ b/src/ts/graphics/graphicsUtils.ts @@ -10,14 +10,13 @@ import { HAlign, VAlign, TextOptions, lineBreak, drawTextAligned, measureText, drawText, drawOutlinedText } from '../graphics/spriteFont'; import * as sprites from '../generated/sprites'; -import { fontPal, fontSmallPal } from '../client/fonts'; -import { getPonyChatHeight, isPony } from '../common/pony'; +import { fontPal, fontSmallPal } from '../common/fonts'; import { worldToScreen } from '../common/camera'; import { multiplyColor, colorToCSS } from '../common/color'; import { getTag, getTagPalette } from '../common/tags'; import { rect } from '../common/rect'; import { mockPaletteManager } from '../common/ponyInfo'; -import { sortEntities, isHidden, isFriend } from '../common/entityUtils'; +import { sortEntities, isHidden, isFriend, isPony, getPonyChatHeight } from '../common/entityUtils'; const baloonTaper = [ { w: 1, y: 2 }, diff --git a/src/ts/graphics/paletteSpriteBatch.ts b/src/ts/graphics/paletteSpriteBatch.ts index 64dd55d..ae81a2e 100644 --- a/src/ts/graphics/paletteSpriteBatch.ts +++ b/src/ts/graphics/paletteSpriteBatch.ts @@ -1,7 +1,7 @@ import { Sprite, Palette, PaletteSpriteBatch as IPaletteSpriteBatch, Matrix2D, Batch } from '../common/interfaces'; import { BaseSpriteBatch, getColorFloat } from './baseSpriteBatch'; import { colorFromRGBA, colorToFloat } from '../common/color'; -import { createSprite } from '../client/spriteUtils'; +import { createSprite } from '../common/spriteUtils'; import { createPalette } from './paletteManager'; const defaultRectSprite = createSprite(0, 0, 1, 1, 0, 0, 3); diff --git a/src/ts/graphics/spriteFont.ts b/src/ts/graphics/spriteFont.ts index 673be5e..3973260 100644 --- a/src/ts/graphics/spriteFont.ts +++ b/src/ts/graphics/spriteFont.ts @@ -1,7 +1,7 @@ import { Rect, Sprite, SpriteBatch, PaletteSpriteBatch, Palette, isPaletteSpriteBatch } from '../common/interfaces'; import { WHITE } from '../common/colors'; import { stringToCodesTemp, codesBuffer } from '../common/stringUtils'; -import { createSprite } from '../client/spriteUtils'; +import { createSprite } from '../common/spriteUtils'; export const enum HAlign { Left, diff --git a/src/ts/graphics/webgl/glVao.ts b/src/ts/graphics/webgl/glVao.ts index caf9c25..6f3f046 100644 --- a/src/ts/graphics/webgl/glVao.ts +++ b/src/ts/graphics/webgl/glVao.ts @@ -1,4 +1,4 @@ -import { timeStart, timeEnd } from '../../client/timing'; +import { timeStart, timeEnd } from '../../common/timing'; export interface VAOAttributes { name: string; diff --git a/src/ts/server/accountUtils.ts b/src/ts/server/accountUtils.ts index fbf83e1..65af2ab 100644 --- a/src/ts/server/accountUtils.ts +++ b/src/ts/server/accountUtils.ts @@ -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; diff --git a/src/ts/server/adminServerActions.ts b/src/ts/server/adminServerActions.ts index 570eb6a..32504b0 100644 --- a/src/ts/server/adminServerActions.ts +++ b/src/ts/server/adminServerActions.ts @@ -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(); constructor( - private client: ClientAdminActions & ClientExtensions, + private client: ClientAdminActionsTemplate & ClientExtensions, private server: ServerConfig, private settings: Settings, private adminService: AdminService, diff --git a/src/ts/server/api/account.ts b/src/ts/server/api/account.ts index 0b28949..0ed5f86 100644 --- a/src/ts/server/api/account.ts +++ b/src/ts/server/api/account.ts @@ -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; export type UpdateAccount = ReturnType; diff --git a/src/ts/server/api/pony.ts b/src/ts/server/api/pony.ts index 1f9b3cb..3759b42 100644 --- a/src/ts/server/api/pony.ts +++ b/src/ts/server/api/pony.ts @@ -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) : ''; diff --git a/src/ts/server/canvasUtilsNode.ts b/src/ts/server/canvasUtilsNode.ts index a9d840a..4f13f1c 100644 --- a/src/ts/server/canvasUtilsNode.ts +++ b/src/ts/server/canvasUtilsNode.ts @@ -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; diff --git a/src/ts/server/characterUtils.ts b/src/ts/server/characterUtils.ts index 757919f..1c23cf6 100644 --- a/src/ts/server/characterUtils.ts +++ b/src/ts/server/characterUtils.ts @@ -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'; diff --git a/src/ts/server/chat.ts b/src/ts/server/chat.ts index cdb1300..c6375d1 100644 --- a/src/ts/server/chat.ts +++ b/src/ts/server/chat.ts @@ -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); diff --git a/src/ts/server/commands.ts b/src/ts/server/commands.ts index 16043a5..592fda2 100644 --- a/src/ts/server/commands.ts +++ b/src/ts/server/commands.ts @@ -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; diff --git a/src/ts/server/controllers/plantController.ts b/src/ts/server/controllers/plantController.ts index 49bbd1b..6505d86 100644 --- a/src/ts/server/controllers/plantController.ts +++ b/src/ts/server/controllers/plantController.ts @@ -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; diff --git a/src/ts/server/db.ts b/src/ts/server/db.ts index 5a42fd4..34c09f5 100644 --- a/src/ts/server/db.ts +++ b/src/ts/server/db.ts @@ -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'; diff --git a/src/ts/server/entityUtils.ts b/src/ts/server/entityUtils.ts index a62fd7b..14fb91f 100644 --- a/src/ts/server/entityUtils.ts +++ b/src/ts/server/entityUtils.ts @@ -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; diff --git a/src/ts/server/mapUtils.ts b/src/ts/server/mapUtils.ts index 63383c9..998d132 100644 --- a/src/ts/server/mapUtils.ts +++ b/src/ts/server/mapUtils.ts @@ -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'; diff --git a/src/ts/server/maps/houseMap.ts b/src/ts/server/maps/houseMap.ts index 142ab79..58961b1 100644 --- a/src/ts/server/maps/houseMap.ts +++ b/src/ts/server/maps/houseMap.ts @@ -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; diff --git a/src/ts/server/playerUtils.ts b/src/ts/server/playerUtils.ts index f0c7c5b..b629069 100644 --- a/src/ts/server/playerUtils.ts +++ b/src/ts/server/playerUtils.ts @@ -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, diff --git a/src/ts/server/regionUtils.ts b/src/ts/server/regionUtils.ts index 70c5bc6..2c66d8d 100644 --- a/src/ts/server/regionUtils.ts +++ b/src/ts/server/regionUtils.ts @@ -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; diff --git a/src/ts/server/server.ts b/src/ts/server/server.ts index 41a8c71..ab9f276 100644 --- a/src/ts/server/server.ts +++ b/src/ts/server/server.ts @@ -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'); diff --git a/src/ts/server/serverActions.ts b/src/ts/server/serverActions.ts index d30ed88..a1b187d 100644 --- a/src/ts/server/serverActions.ts +++ b/src/ts/server/serverActions.ts @@ -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; diff --git a/src/ts/server/serverActionsManager.ts b/src/ts/server/serverActionsManager.ts index d165fee..a24af64 100644 --- a/src/ts/server/serverActionsManager.ts +++ b/src/ts/server/serverActionsManager.ts @@ -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); diff --git a/src/ts/server/serverInterfaces.ts b/src/ts/server/serverInterfaces.ts index 1912b07..028820b 100644 --- a/src/ts/server/serverInterfaces.ts +++ b/src/ts/server/serverInterfaces.ts @@ -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 { editingLocked: boolean; } -export interface IClient extends ClientActions, ClientExtensions { +export interface IClient extends ClientActionsTemplate, ClientExtensions { // origin info ip: string; country: string; diff --git a/src/ts/server/serverMap.ts b/src/ts/server/serverMap.ts index 560c84b..d84f577 100644 --- a/src/ts/server/serverMap.ts +++ b/src/ts/server/serverMap.ts @@ -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; diff --git a/src/ts/server/serverRegion.ts b/src/ts/server/serverRegion.ts index 19e24c5..b5c9025 100644 --- a/src/ts/server/serverRegion.ts +++ b/src/ts/server/serverRegion.ts @@ -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; diff --git a/src/ts/server/start.ts b/src/ts/server/start.ts index 4bbd93f..50448cf 100644 --- a/src/ts/server/start.ts +++ b/src/ts/server/start.ts @@ -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'; diff --git a/src/ts/server/world.ts b/src/ts/server/world.ts index 30cd572..d6e24fb 100644 --- a/src/ts/server/world.ts +++ b/src/ts/server/world.ts @@ -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'; diff --git a/src/ts/tests/client/canvasUtils.spec.ts b/src/ts/tests/client/canvasUtils.spec.ts index 941ff26..1c5ea48 100644 --- a/src/ts/tests/client/canvasUtils.spec.ts +++ b/src/ts/tests/client/canvasUtils.spec.ts @@ -1,6 +1,6 @@ import '../lib'; import { expect } from 'chai'; -import { resizeCanvas, resizeCanvasWithRatio } from '../../client/canvasUtils'; +import { resizeCanvas, resizeCanvasWithRatio } from '../../common/canvasUtils'; describe('canvasUtils', () => { describe('resizeCanvas()', () => { diff --git a/src/ts/tests/client/clientActions.spec.ts b/src/ts/tests/client/clientActions.spec.ts index 6fb9225..80d5dcd 100644 --- a/src/ts/tests/client/clientActions.spec.ts +++ b/src/ts/tests/client/clientActions.spec.ts @@ -20,9 +20,10 @@ import { createCamera } from '../../common/camera'; import { commonPalettes } from '../../graphics/graphicsUtils'; import { Model } from '../../components/services/model'; import { createRegion } from '../../common/region'; -import { getTile, addEntity, setRegion, createWorldMap } from '../../common/worldMap'; +import { addEntity, setRegion, createWorldMap } from '../../client/worldMap'; import { createServerRegion } from '../../server/serverRegion'; import { ServerRegion } from '../../server/serverInterfaces'; +import { getTile } from '../../common/tileUtils'; describe('ClientActions', () => { let zone: NgZone; diff --git a/src/ts/tests/client/clientUtils.spec.ts b/src/ts/tests/client/clientUtils.spec.ts index bf35ec2..b858407 100644 --- a/src/ts/tests/client/clientUtils.spec.ts +++ b/src/ts/tests/client/clientUtils.spec.ts @@ -1,11 +1,12 @@ import '../lib'; import { expect } from 'chai'; import { - cleanName, cleanMessage, filterString, isSpamMessage, toSocialSiteInfo + isSpamMessage, toSocialSiteInfo } from '../../client/clientUtils'; import { repeat, removeItem } from '../../common/utils'; import { SAY_MAX_LENGTH } from '../../common/constants'; import { oauthProviders } from '../../client/data'; +import { cleanMessage, cleanName, filterString } from '../../common/stringUtils'; const cleanNameTests: [string | undefined, string, string][] = [ [undefined, '', 'undefined'], diff --git a/src/ts/tests/client/emoji.spec.ts b/src/ts/tests/client/emoji.spec.ts index 128e859..f8cf6f3 100644 --- a/src/ts/tests/client/emoji.spec.ts +++ b/src/ts/tests/client/emoji.spec.ts @@ -1,6 +1,6 @@ import '../lib'; import { expect } from 'chai'; -import { splitEmojis, findEmoji, replaceEmojis, emojis, hasEmojis, autocompleteMesssage } from '../../client/emoji'; +import { splitEmojis, findEmoji, replaceEmojis, emojis, hasEmojis, autocompleteMesssage } from '../../common/emoji'; describe('emotes', () => { describe('findEmote()', () => { diff --git a/src/ts/tests/client/ponyDraw.spec.ts b/src/ts/tests/client/ponyDraw.spec.ts index bd42ec5..f5a9a1f 100644 --- a/src/ts/tests/client/ponyDraw.spec.ts +++ b/src/ts/tests/client/ponyDraw.spec.ts @@ -2,10 +2,10 @@ import { compareCanvases, loadSprites, loadImageAsCanvas, clearCompareResults } from '../lib'; import * as path from 'path'; import { TRANSPARENT, blushColor, WHITE } from '../../common/colors'; -import { defaultPonyState, defaultDrawPonyOptions } from '../../client/ponyHelpers'; +import { defaultPonyState, defaultDrawPonyOptions } from '../../common/ponyHelpers'; import { mockPaletteManager, createDefaultPony } from '../../common/ponyInfo'; import { PonyState, PalettePonyInfo, PonyInfo, DrawPonyOptions, NoDraw } from '../../common/interfaces'; -import { sit, trot, sitDown, laugh, fly } from '../../client/ponyAnimations'; +import { sit, trot, sitDown, laugh, fly } from '../../common/ponyAnimations'; import { drawCanvas } from '../../graphics/contextSpriteBatch'; import { parseExpression } from '../../common/expressionUtils'; import { compressPonyString, decodePonyInfo } from '../../common/compressPony'; diff --git a/src/ts/tests/client/ponyStates.spec.ts b/src/ts/tests/client/ponyStates.spec.ts index 35db6da..d411f4e 100644 --- a/src/ts/tests/client/ponyStates.spec.ts +++ b/src/ts/tests/client/ponyStates.spec.ts @@ -4,9 +4,9 @@ import { trotting, flying, standing, lying, sitting, hovering, toBoopState, booping, boopingSitting, boopingLying, boopingFlying, sittingDown, isFlyingUp, flyingUp, trottingToFlying, flyingToTrotting, flyingDown, isFlyingUpOrDown, isFlyingDown -} from '../../client/ponyStates'; +} from '../../common/ponyStates'; import { EntityState } from '../../common/interfaces'; -import { flagsToState } from '../../common/pony'; +import { flagsToState } from '../../client/pony'; describe('ponyStates', () => { describe('flagsToState()', () => { diff --git a/src/ts/tests/client/spriteFont.spec.ts b/src/ts/tests/client/spriteFont.spec.ts index b9a8663..17dfee9 100644 --- a/src/ts/tests/client/spriteFont.spec.ts +++ b/src/ts/tests/client/spriteFont.spec.ts @@ -1,7 +1,7 @@ import { compareCanvases, loadSprites, loadImageAsCanvas, clearCompareResults } from '../lib'; import { expect } from 'chai'; import { WHITE, BLACK } from '../../common/colors'; -import { fontPal } from '../../client/fonts'; +import { fontPal } from '../../common/fonts'; import { drawCanvas, ContextSpriteBatch } from '../../graphics/contextSpriteBatch'; import { pathTo } from '../../server/paths'; import { paletteSpriteSheet } from '../../generated/sprites'; diff --git a/src/ts/tests/client/worldMap.spec.ts b/src/ts/tests/client/worldMap.spec.ts index 1fdee5f..aed3a26 100644 --- a/src/ts/tests/client/worldMap.spec.ts +++ b/src/ts/tests/client/worldMap.spec.ts @@ -2,15 +2,15 @@ import '../lib'; import { Subject } from 'rxjs'; import { expect } from 'chai'; import { useFakeTimers, SinonFakeTimers } from 'sinon'; -import { getRegion, addEntity, setRegion, createWorldMap } from '../../common/worldMap'; +import { addEntity, setRegion, createWorldMap } from '../../client/worldMap'; import { PonyTownGame } from '../../client/game'; import { MessageType, Entity, Pony, TileType, EntityState, DecodedUpdate } from '../../common/interfaces'; import { entity, mock } from '../mocks'; import { rect } from '../../common/rect'; import { pony, apple } from '../../common/entities'; import { createAnimator } from '../../common/animator'; -import { defaultPonyState } from '../../client/ponyHelpers'; -import { createRegion } from '../../common/region'; +import { defaultPonyState } from '../../common/ponyHelpers'; +import { createRegion, getRegion } from '../../common/region'; import { createCamera } from '../../common/camera'; import { chatAnimationDuration } from '../../graphics/graphicsUtils'; import { handleUpdateEntity, handleSays } from '../../client/handlers'; diff --git a/src/ts/tests/common/collision.spec.ts b/src/ts/tests/common/collision.spec.ts index 6290da7..93af208 100644 --- a/src/ts/tests/common/collision.spec.ts +++ b/src/ts/tests/common/collision.spec.ts @@ -8,7 +8,7 @@ import { ServerRegion } from '../../server/serverInterfaces'; import { PONY_TYPE, tileWidth, tileHeight } from '../../common/constants'; import { generateRegionCollider } from '../../common/region'; import { ponyColliders } from '../../common/mixins'; -import { updateTileIndices } from '../../client/tileUtils'; +import { updateTileIndices } from '../../common/tileUtils'; export function colliders(x: number, y: number, w: number, h: number, tall = true, exact = false): Collider[] { return [{ x, y, w, h, tall, exact }]; diff --git a/src/ts/tests/common/expressionUtils.spec.ts b/src/ts/tests/common/expressionUtils.spec.ts index 0b0233b..f56df65 100644 --- a/src/ts/tests/common/expressionUtils.spec.ts +++ b/src/ts/tests/common/expressionUtils.spec.ts @@ -4,7 +4,7 @@ import { parseExpression, expression } from '../../common/expressionUtils'; import { expressions } from '../../common/expressions'; import { Expression, Iris, Eye, Muzzle, ExpressionExtra } from '../../common/interfaces'; import { decodeExpression, encodeExpression } from '../../common/encoders/expressionEncoder'; -import { flipIris } from '../../client/ponyUtils'; +import { flipIris } from '../../common/ponyUtils'; function toExpression([right, left, muzzle, rightIris = 0, leftIris = 0, extra = 0]: any): Expression { return { left, right, muzzle, rightIris, leftIris, extra }; diff --git a/src/ts/tests/common/ponyHelpers.spec.ts b/src/ts/tests/common/ponyHelpers.spec.ts index ff8439a..fd6e375 100644 --- a/src/ts/tests/common/ponyHelpers.spec.ts +++ b/src/ts/tests/common/ponyHelpers.spec.ts @@ -1,6 +1,6 @@ import '../lib'; import { expect } from 'chai'; -import { defaultPonyState, isStateEqual } from '../../client/ponyHelpers'; +import { defaultPonyState, isStateEqual } from '../../common/ponyHelpers'; describe('interfaces', () => { describe('isStateEqual()', () => { diff --git a/src/ts/tests/graphics/spriteSheetUtils.spec.ts b/src/ts/tests/graphics/spriteSheetUtils.spec.ts index 4e19b01..f0d369d 100644 --- a/src/ts/tests/graphics/spriteSheetUtils.spec.ts +++ b/src/ts/tests/graphics/spriteSheetUtils.spec.ts @@ -2,7 +2,7 @@ import '../lib'; import { expect } from 'chai'; import { stub, assert } from 'sinon'; import { createTexturesForSpriteSheets } from '../../graphics/spriteSheetUtils'; -import { createCanvas } from '../../client/canvasUtils'; +import { createCanvas } from '../../common/canvasUtils'; import { SpriteSheet } from '../../common/interfaces'; function createImageData() { diff --git a/src/ts/tests/lib.ts b/src/ts/tests/lib.ts index 0276b23..9cbd1fd 100644 --- a/src/ts/tests/lib.ts +++ b/src/ts/tests/lib.ts @@ -8,13 +8,13 @@ import * as del from 'del'; import { once, mapValues } from 'lodash'; import { spawnSync } from 'child_process'; import { createStubInstance, SinonStubbedInstance, stub } from 'sinon'; -import { loadAndInitSheets } from '../client/spriteUtils'; import '../server/canvasUtilsNode'; import { setPaletteManager } from '../common/mixins'; import { mockPaletteManager } from '../common/ponyInfo'; import { spriteSheets } from '../generated/sprites'; import { pathTo } from '../server/paths'; import { loadImage, loadImageSync, createCanvas } from '../server/canvasUtilsNode'; +import { loadAndInitSheets } from '../client/loadSprites'; require('chai').use(require('chai-as-promised')); diff --git a/src/ts/tests/mocks.ts b/src/ts/tests/mocks.ts index c46fac9..965340c 100644 --- a/src/ts/tests/mocks.ts +++ b/src/ts/tests/mocks.ts @@ -4,14 +4,14 @@ import { Subject } from 'rxjs'; import { SinonStubbedInstance, stub } from 'sinon'; import { IClient, Reporter, ServerEntity, ServerRegion } from '../server/serverInterfaces'; import { IAccount, ICharacter, IAuth } from '../server/db'; -import { ClientActions } from '../client/clientActions'; import { Entity, IMap, defaultWorldState } from '../common/interfaces'; import { createServerMap } from '../server/serverMap'; import { createCamera } from '../common/camera'; -import { getRegionGlobal } from '../common/worldMap'; import { mixColliderRect } from '../common/mixins'; import { createBinaryWriter } from 'ag-sockets'; import { PONY_TYPE } from '../common/constants'; +import { getRegionGlobal } from '../common/region'; +import { ClientActionsTemplate } from '../common/clientActionsTemplte'; export function auth(item: Partial): IAuth { return item as IAuth; @@ -106,7 +106,7 @@ export function mockClient(fields: any = {}): IClient { ...fields, }; - const client = mock(ClientActions, partial) as IClient; + const client = mock(ClientActionsTemplate, partial) as IClient; client.pony.client = client; return client; diff --git a/src/ts/tests/server/mapUtils.spec.ts b/src/ts/tests/server/mapUtils.spec.ts index 3e031ed..cb2929d 100644 --- a/src/ts/tests/server/mapUtils.spec.ts +++ b/src/ts/tests/server/mapUtils.spec.ts @@ -4,7 +4,7 @@ import { createServerMap, findEntities, findClosestEntity } from '../../server/s import { serverEntity } from '../mocks'; import { ServerEntity, ServerMap, ServerRegion } from '../../server/serverInterfaces'; import { addEntityToRegion } from '../../server/serverRegion'; -import { getRegion } from '../../common/worldMap'; +import { getRegion } from '../../common/region'; describe('mapUtils', () => { let map: ServerMap; diff --git a/src/ts/tests/server/playerUtils.spec.ts b/src/ts/tests/server/playerUtils.spec.ts index 543ed57..24d8b62 100644 --- a/src/ts/tests/server/playerUtils.spec.ts +++ b/src/ts/tests/server/playerUtils.spec.ts @@ -17,11 +17,11 @@ import { createServerRegion } from '../../server/serverRegion'; import { rect } from '../../common/rect'; import { CounterService } from '../../server/services/counter'; import { createCamera } from '../../common/camera'; -import { getRegion } from '../../common/worldMap'; import { createServerMap } from '../../server/serverMap'; import { createBinaryWriter, getWriterBuffer } from 'ag-sockets'; import { sendAction } from '../../server/entityUtils'; import { updateColliders } from '../common/collision.spec'; +import { getRegion } from '../../common/region'; describe('playerUtils', () => { const def = { x: 0, y: 0, vx: 0, vy: 0, action: 0, playerState: 0, options: undefined }; diff --git a/src/ts/tests/server/regionUtils.spec.ts b/src/ts/tests/server/regionUtils.spec.ts index bfa73f9..0b229a2 100644 --- a/src/ts/tests/server/regionUtils.spec.ts +++ b/src/ts/tests/server/regionUtils.spec.ts @@ -10,8 +10,8 @@ import { IClient, ServerRegion } from '../../server/serverInterfaces'; import { addEntityToRegion, createServerRegion } from '../../server/serverRegion'; import { createServerMap } from '../../server/serverMap'; import { mockClient, serverEntity } from '../mocks'; -import { getRegion } from '../../common/worldMap'; import { EntityFlags } from '../../common/interfaces'; +import { getRegion } from '../../common/region'; describe('regionUtils', () => { let client: IClient; diff --git a/src/ts/tests/server/serverMap.spec.ts b/src/ts/tests/server/serverMap.spec.ts index b38a085..63df7bd 100644 --- a/src/ts/tests/server/serverMap.spec.ts +++ b/src/ts/tests/server/serverMap.spec.ts @@ -1,8 +1,8 @@ import '../lib'; import { expect } from 'chai'; import { createServerMap } from '../../server/serverMap'; -import { getRegion, getRegionGlobal } from '../../common/worldMap'; import { ServerMap } from '../../server/serverInterfaces'; +import { getRegion, getRegionGlobal } from '../../common/region'; describe('serverMap', () => { let map: ServerMap;