Split client code from server

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

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