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;