Commit d0b09dd1 authored by 邱旭's avatar 邱旭

feat:merge

parent 7f48798a
node_modules/
dist/
build/
released/resource/
yarn-error.log
debug/
.DS_Store
# 红包雨
## 导出
```typescript
enum GAME_EVENT {
READY = "READY", // 初始化完成
START_GAME = "START_GAME",
END_GAME = "END_GAME",
ADD_SCORE = "ADD_SCORE", // 分辨增加
ON_SHOW = 'ON_SHOW', // 页面显示
ON_HIDE = 'ON_HIDE', // 页面隐藏
}
interface IConfig {
dropSpeed?: number, // 掉落速度(px/s)
interval?: number, // 掉落间隔事件(s)
rainObj?: string, // 掉落物图片
}
// 设置参数
function setConfig(obj: IConfig) {
/* ... */
};
```
## 作为模块使用
将项目源代码粘入你的项目中,修改当前项目的package.json中的`useAsModule`改为true,在根项目的package.json中修改/添加以下内容
```text
"workspaces": [
"src/game_module" // 修改为你的模块路径
],
"scripts": {
"dev": "cross-env NODE_ENV=development node ./config/scripts/assets/generateAssetList.js && concurrently \"cd ./src/game_module && yarn dev\" \"node ./config/webpack.dev.config.js\"",
"prod:game": "cd ./src/game_module && yarn build",
"prod:main": "cross-env NODE_ENV=production node ./config/webpack.prod.config.js",
"prod:all": "cross-env NODE_ENV=production yarn prod:game && node ./config/webpack.prod.config.js",
"build": "cross-env NODE_ENV=production yarn prod:game && node ./config/scripts/assets/generateAssetList.js && node ./config/scripts/assets/index.js imgmin imgup && node ./config/webpack.prod.config.js"
},
```
## 使用案例
```jsx
import React, { Component } from 'react';
import { Game, setConfig, GDispatcher, GAME_EVENT } from "../../../debug/output.module";
import './GamePage.less';
export default class GamePage extends Component {
div = null;
game = null;
componentDidMount() {
const canvas = document.createElement("canvas");
canvas.style = "width:100%;height:100%";
this.div.appendChild(canvas);
this.game = new Game(canvas);
// 注册触摸事件
this.game.initWebEvent();
// 设置参数
setConfig({
dropSpeed: 750,
interval: 0.05,
});
// 等待READY事件表示可以开始游戏
GDispatcher.once(GAME_EVENT.READY, () => {
// 触发开始游戏事件
GDispatcher.dispatchEvent(GAME_EVENT.START_GAME);
});
}
componentWillUnmount() {
this.game.destroy();
}
render() {
return <div
className="game-page"
ref={(div) => this.div = div}
/>;
}
}
```
/*
* index.mjs
* Created by 还有醋v on 2022/5/27.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
/**
* 插入banner变量
* @param {{values:{[key in string]: string|number|Function<string|number>}}} options
*/
export default function pluginBannerVariable(options) {
const { values } = options;
return {
name: "banner-variable",
banner() {
let code = "var ";
for (const key in values) {
const value = values[key] instanceof Function ? values[key]() : values[key];
code += `${key}=${value},`;
}
code = code.slice(0, code.length - 1) + ";";
return code;
},
}
}
/*
* utils.mjs.js
* Created by 还有醋v on 2022/5/27.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
import childProcess from "child_process";
export function _debounce(fn, delay = 1000) {
let timer = null;
return function (...args) {
timer && clearTimeout(timer);
timer = setTimeout(fn, delay, ...args);
};
}
export function runScript(scriptPath, callback) {
let invoked = false;
const process = childProcess.fork(scriptPath);
process.on('error', (err) => {
if (invoked) return;
invoked = true;
callback(err);
});
process.on('exit', (code) => {
if (invoked) return;
invoked = true;
const err = code === 0 ? null : new Error('exit code ' + code);
callback(err);
});
}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>new_game_template</title>
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="full-screen" content="true"/>
<meta name="screen-orientation" content="portrait"/>
<meta name="x5-fullscreen" content="true"/>
<meta name="360-fullscreen" content="true"/>
<!-- 渲染引擎 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge_2.0.44_fixed_HMS.js" crossorigin="anonymous"></script>
<!--<script src="libs/fyge.min.js" crossorigin="anonymous"></script>-->
<!-- svga解析库 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script>
<!-- 放声音的 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/howler.min.js" crossorigin="anonymous"></script>
<style>
html,
body {
padding: 0;
margin: 0;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
position: absolute;
background-color: #ffffff;
}
#__loading__ {
position: absolute;
left: 50%;
top: 50%;
margin-left: -45px;
color: #ffffff;
}
#cusEngine {
line-height: 0;
font-size: 0;
position: absolute;
}
#canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="__loading__">拼命加载中...</div>
<div id="cusEngine">
<canvas id="canvas"></canvas>
</div>
<!-- 帧率检测 -->
<!-- <script src="https://yun.duiba.com.cn/db_games/libs0126/stats.js"></script> -->
<script>
const app = {
checkMember: () => {
return false;
}
};
function getApp() {
return app;
}
// document.oncontextmenu = () => false;
</script>
<script>
var CFG = CFG || {};
CFG.projectId = 'pa525eacc';//线上直接写死
CFG.appID = '76177';//线上直接写死
//TODO我的奖品链接
window["recordUrl"] = "fe071865b.html";
window.addEventListener("load", function () {
//获取canvas
var canvas = document.getElementById("canvas");
canvas.width = document.body.clientWidth * (window.devicePixelRatio || 1)
canvas.height = document.body.clientHeight * (window.devicePixelRatio || 1)
var main = new output.Game(canvas);
main.initWebEvent();
window.stage = main.stage
})
</script>
<!-- 构建的js -->
<script src="./debug/output.js" crossorigin="anonymous"></script>
<!--test btn-->
<div style="
background-color:#aaaaaa;
width: 100px;
height: 50px;
position: fixed;
top: 0;
z-index: 99;
display: flex;
align-items: center;
justify-content: center"
onclick="output.GDispatcher.dispatchEvent(output.GAME_EVENT.START_GAME)"
>
开始游戏
</div>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
declare module SvgaParser {
/**
* 加载方法
* @param url 资源路径
* @param success
* @param failure
*/
export function loadSvga(url: string, success: (videoItem: VideoEntity) => void, failure?: (err: string) => void): void;
/**
* 导出只是当作类型接口用
*/
export interface VideoEntity {
/**
* SVGA 文件版本
*/
version: string;
/**
* 影片尺寸
*/
videoSize: {
width: number;
height: number;
};
/**
* 帧率,60,30等每秒
*/
FPS: number;
/**
* 总帧数
*/
frames: number;
/**
* base64图片数据记录
*/
images: {
[key: string]: string
};
/**
* 图片是否已被缓存,缓存全局,注意名字覆盖
*/
hasBeenCached: boolean;
/**
* sprite对象数据
*/
sprites: SpriteEntity[];
}
interface SpriteEntity {
/**
* 标识
*/
matteKey: string;
/**
* 图片key值
*/
imageKey: string;
/**
* 帧数据数组
*/
frames: FrameEntity[];
}
/**
* 还有很多其他数据,暂不需要,比如矢量路径和遮罩路径暂时都无
*/
interface FrameEntity {
/**
* 透明度
*/
alpha: number;
/**
* 2维矩阵数据
*/
transform: {
a: number,
b: number,
c: number,
d: number,
tx: number,
ty: number,
};
}
}
declare module "svga-parser" { export = SvgaParser; }
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
// Type definitions for howler.js v2.1.1
// Project: https://github.com/goldfire/howler.js
// Definitions by: Pedro Casaubon <https://github.com/xperiments>
// Alexander Leon <https://github.com/alien35>
// Nicholas Higgins <https://github.com/nicholashza>
// Carlos Urango <https://github.com/cjurango>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
interface HowlerGlobal {
mute(muted: boolean): this;
volume(): number;
volume(volume: number): this;
codecs(ext: string): boolean;
unload(): this;
usingWebAudio: boolean;
html5PoolSize: number;
noAudio: boolean;
autoUnlock: boolean;
autoSuspend: boolean;
ctx: AudioContext;
masterGain: GainNode;
stereo(pan: number): this;
pos(x: number, y: number, z: number): this | void;
orientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): this | void;
}
declare let Howler: HowlerGlobal;
interface IHowlSoundSpriteDefinition {
[name: string]: [number, number] | [number, number, boolean]
}
interface IHowlProperties {
src: string | string[];
volume?: number;
html5?: boolean;
loop?: boolean;
preload?: boolean;
autoplay?: boolean;
mute?: boolean;
sprite?: IHowlSoundSpriteDefinition;
rate?: number;
pool?: number;
format?: string[] | string;
xhrWithCredentials?: boolean;
onload?: () => void;
onloaderror?: (soundId: number, error: any) => void;
onplay?: (soundId: number) => void;
onplayerror?: (soundId: number, error: any) => void;
onend?: (soundId: number) => void;
onpause?: (soundId: number) => void;
onstop?: (soundId: number) => void;
onmute?: (soundId: number) => void;
onvolume?: (soundId: number) => void;
onrate?: (soundId: number) => void;
onseek?: (soundId: number) => void;
onfade?: (soundId: number) => void;
onunlock?: (soundId: number) => void;
}
interface Howl {
play(spriteOrId?: string | number): number; // .play() is not chainable; the other methods are
pause(id?: number): this;
stop(id?: number): this;
mute(): boolean;
mute(muted: boolean, id?: number): this;
volume(): number;
volume(idOrSetVolume: number): this | number;
volume(volume: number, id: number): this;
fade(from: number, to: number, duration: number, id?: number): this;
rate(): number;
rate(idOrSetRate: number): this | number;
rate(rate: number, id: number): this;
seek(seek?: number, id?: number): this | number;
loop(id?: number): boolean;
loop(loop: boolean, id?: number): this;
playing(id?: number): boolean;
duration(id?: number): number;
state(): 'unloaded' | 'loading' | 'loaded';
load(): this;
unload(): void;
on(event: 'load', callback: () => void, id?: number): this;
on(event: 'loaderror', callback: (soundId: number, error: any) => void, id?: number): this;
on(event: 'play', callback: (soundId: number) => void, id?: number): this;
on(event: 'playerror', callback: (soundId: number, error: any) => void, id?: number): this;
on(event: 'end', callback: (soundId: number) => void, id?: number): this;
on(event: 'pause', callback: (soundId: number) => void, id?: number): this;
on(event: 'stop', callback: (soundId: number) => void, id?: number): this;
on(event: 'mute', callback: (soundId: number) => void, id?: number): this;
on(event: 'volume', callback: (soundId: number) => void, id?: number): this;
on(event: 'rate', callback: (soundId: number) => void, id?: number): this;
on(event: 'seek', callback: (soundId: number) => void, id?: number): this;
on(event: 'fade', callback: (soundId: number) => void, id?: number): this;
on(event: string, callback: Function, id?: number): this;
on(event: 'unlock', callback: (soundId: number) => void, id?: number): this;
once(event: 'load', callback: () => void, id?: number): this;
once(event: 'loaderror', callback: (soundId: number, error: any) => void, id?: number): this;
once(event: 'play', callback: (soundId: number) => void, id?: number): this;
once(event: 'playerror', callback: (soundId: number, error: any) => void, id?: number): this;
once(event: 'end', callback: (soundId: number) => void, id?: number): this;
once(event: 'pause', callback: (soundId: number) => void, id?: number): this;
once(event: 'stop', callback: (soundId: number) => void, id?: number): this;
once(event: 'mute', callback: (soundId: number) => void, id?: number): this;
once(event: 'volume', callback: (soundId: number) => void, id?: number): this;
once(event: 'rate', callback: (soundId: number) => void, id?: number): this;
once(event: 'seek', callback: (soundId: number) => void, id?: number): this;
once(event: 'fade', callback: (soundId: number) => void, id?: number): this;
once(event: string, callback: Function, id?: number): this;
once(event: 'unlock', callback: (soundId: number) => void, id?: number): this;
off(event: string, callback?: Function, id?: number): this;
off(): this;
stereo(pan: number, id?: number): this | void;
pos(x: number, y: number, z: number, id?: number): this | void;
orientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): this | void;
pannerAttr(o: {
coneInnerAngle?: number,
coneOuterAngle?: number, coneOuterGain?: number,
distanceModel: 'inverse' | 'linear', maxDistance: number,
panningModel: 'HRTF' | 'equalpower', refDistance: number, rolloffFactor: number
}, id?: number): this;
}
interface HowlStatic {
new(properties: IHowlProperties): Howl;
}
declare let Howl: HowlStatic;
declare module "howler" {
export let Howler: HowlerGlobal;
export let Howl: HowlStatic;
}
/*
* lib.d.ts
* Created by 还有醋v on 2022/5/27.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
declare const __ENV__: "development" | "production";
declare const __version__: string;
declare const __buildDate__: string;
declare const __useAsModule__: Boolean;
/**
* shader文件类型
*/
declare module '*.vert' {
const source: string;
export default source;
}
declare module '*.frag' {
const source: string;
export default source;
}
declare module '*.vs' {
const source: string;
export default source;
}
declare module '*.fs' {
const source: string;
export default source;
}
declare module '*.glsl' {
const source: string;
export default source;
}
/* Polyfill service DEVELOPMENT MODE - for live use set NODE_ENV to 'production'
* Disable minification (remove `.min` from URL path) for more info */
(function(self, undefined) {function ArrayCreate(r){if(1/r==-1/0&&(r=0),r>Math.pow(2,32)-1)throw new RangeError("Invalid array length");var a=[];return a.length=r,a}function Call(t,l){var n=arguments.length>2?arguments[2]:[];if(!1===IsCallable(t))throw new TypeError(Object.prototype.toString.call(t)+"is not a function.");return t.apply(l,n)}function CreateDataProperty(e,r,t){var a={value:t,writable:!0,enumerable:!0,configurable:!0};try{return Object.defineProperty(e,r,a),!0}catch(e){return!1}}function CreateDataPropertyOrThrow(t,r,o){var e=CreateDataProperty(t,r,o);if(!e)throw new TypeError("Cannot assign value `"+Object.prototype.toString.call(o)+"` to property `"+Object.prototype.toString.call(r)+"` on object `"+Object.prototype.toString.call(t)+"`");return e}function CreateMethodProperty(e,r,t){var a={value:t,writable:!0,enumerable:!1,configurable:!0};Object.defineProperty(e,r,a)}function Get(n,t){return n[t]}function IsCallable(n){return"function"==typeof n}function RequireObjectCoercible(e){if(null===e||void 0===e)throw TypeError(Object.prototype.toString.call(e)+" is not coercible to Object.");return e}function SameValueNonNumber(e,n){return e===n}function ToBoolean(o){return Boolean(o)}function ToObject(r){if(null===r||void 0===r)throw TypeError();return Object(r)}function GetV(t,e){return ToObject(t)[e]}function GetMethod(e,l){var t=GetV(e,l);if(null!==t&&void 0!==t){if(!1===IsCallable(t))throw new TypeError("Method not callable: "+l);return t}}function Invoke(n,e){var t=arguments.length>2?arguments[2]:[],l=GetV(n,e);return Call(l,n,t)}function Type(e){switch(typeof e){case"undefined":return"undefined";case"boolean":return"boolean";case"number":return"number";case"string":return"string";case"symbol":return"symbol";default:return null===e?"null":"Symbol"in self&&(e instanceof self.Symbol||e.constructor===self.Symbol)?"symbol":"object"}}function CreateIterResultObject(e,r){if("boolean"!==Type(r))throw new Error;var t={};return CreateDataProperty(t,"value",e),CreateDataProperty(t,"done",r),t}function GetPrototypeFromConstructor(t,o){var r=Get(t,"prototype");return"object"!==Type(r)&&(r=o),r}function OrdinaryCreateFromConstructor(r,e){var t=arguments[2]||{},o=GetPrototypeFromConstructor(r,e),a=Object.create(o);for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&Object.defineProperty(a,n,{configurable:!0,enumerable:!1,writable:!0,value:t[n]});return a}var GetSubstitution=function(){function e(e){return/^[0-9]$/.test(e)}return function t(n,r,l,i,a,f){for(var s=n.length,h=r.length,c=l+s,u=i.length,v="",g=0;g<f.length;g+=1){var o=f.charAt(g),$=g+1>=f.length,d=g+2>=f.length;if("$"!==o||$)v+=f.charAt(g);else{var p=f.charAt(g+1);if("$"===p)v+="$",g+=1;else if("&"===p)v+=n,g+=1;else if("`"===p)v+=0===l?"":r.slice(0,l-1),g+=1;else if("'"===p)v+=c>=h?"":r.slice(c),g+=1;else{var A=d?null:f.charAt(g+2);if(!e(p)||"0"===p||!d&&e(A))if(e(p)&&(d||e(A))){var y=p+A,I=parseInt(y,10)-1;v+=y<=u&&"Undefined"===Type(i[I])?"":i[I],g+=2}else v+="$";else{var T=parseInt(p,10);v+=T<=u&&"Undefined"===Type(i[T-1])?"":i[T-1],g+=1}}}}return v}}();function IsConstructor(t){return"object"===Type(t)&&("function"==typeof t&&!!t.prototype)}function Construct(r){var t=arguments.length>2?arguments[2]:r,o=arguments.length>1?arguments[1]:[];if(!IsConstructor(r))throw new TypeError("F must be a constructor.");if(!IsConstructor(t))throw new TypeError("newTarget must be a constructor.");if(t===r)return new(Function.prototype.bind.apply(r,[null].concat(o)));var n=OrdinaryCreateFromConstructor(t,Object.prototype);return Call(r,n,o)}function IsRegExp(e){if("object"!==Type(e))return!1;var t="Symbol"in self&&"match"in self.Symbol?Get(e,self.Symbol.match):void 0;if(void 0!==t)return ToBoolean(t);try{var l=e.lastIndex;return e.lastIndex=0,RegExp.prototype.exec.call(e),!0}catch(e){}finally{e.lastIndex=l}return!1}function IteratorClose(r,t){if("object"!==Type(r["[[Iterator]]"]))throw new Error(Object.prototype.toString.call(r["[[Iterator]]"])+"is not an Object.");var e=r["[[Iterator]]"],o=GetMethod(e,"return");if(void 0===o)return t;try{var n=Call(o,e)}catch(r){var a=r}if(t)return t;if(a)throw a;if("object"!==Type(n))throw new TypeError("Iterator's return method returned a non-object.");return t}function IteratorComplete(t){if("object"!==Type(t))throw new Error(Object.prototype.toString.call(t)+"is not an Object.");return ToBoolean(Get(t,"done"))}function IteratorNext(t){if(arguments.length<2)var e=Call(t["[[NextMethod]]"],t["[[Iterator]]"]);else e=Call(t["[[NextMethod]]"],t["[[Iterator]]"],[arguments[1]]);if("object"!==Type(e))throw new TypeError("bad iterator");return e}function IteratorStep(t){var r=IteratorNext(t);return!0!==IteratorComplete(r)&&r}function IteratorValue(t){if("object"!==Type(t))throw new Error(Object.prototype.toString.call(t)+"is not an Object.");return Get(t,"value")}function OrdinaryToPrimitive(r,t){if("string"===t)var e=["toString","valueOf"];else e=["valueOf","toString"];for(var i=0;i<e.length;++i){var n=e[i],a=Get(r,n);if(IsCallable(a)){var o=Call(a,r);if("object"!==Type(o))return o}}throw new TypeError("Cannot convert to primitive.")}function RegExpExec(e,l){var r=Get(e,"exec");if(IsCallable(r)){var t=Call(r,e,[l]);if("object"!==Type(t)&&"null"!==Type(t))throw new TypeError("Invalid result: must be an object or null.");return t}return Call(RegExp.prototype.exec,e,[l])}function SameValueZero(e,a){return Type(e)===Type(a)&&("number"===Type(e)?!(!isNaN(e)||!isNaN(a))||(1/e==1/0&&1/a==-1/0||(1/e==-1/0&&1/a==1/0||e===a)):SameValueNonNumber(e,a))}function SpeciesConstructor(o,r){var t=Get(o,"constructor");if(void 0===t)return r;if("object"!==Type(t))throw new TypeError("O.constructor is not an Object");var e="function"==typeof self.Symbol&&"symbol"==typeof self.Symbol.species?t[self.Symbol.species]:void 0;if(void 0===e||null===e)return r;if(IsConstructor(e))return e;throw new TypeError("No constructor found")}function StringIndexOf(r,n,e){var f=r.length;if(""===n&&e<=f)return e;for(var t=n.length,a=e,i=-1;a+t<=f;){for(var g=!0,o=0;o<t;o+=1)if(r[a+o]!==n[o]){g=!1;break}if(g){i=a;break}a+=1}return i}function ToInteger(r){if("symbol"===Type(r))throw new TypeError("Cannot convert a Symbol value to a number");var o=Number(r);return isNaN(o)?0:1/o==1/0||1/o==-1/0||o===1/0||o===-1/0?o:(o<0?-1:1)*Math.floor(Math.abs(o))}function ToLength(n){var t=ToInteger(n);return t<=0?0:Math.min(t,Math.pow(2,53)-1)}function ToPrimitive(e){var t=arguments.length>1?arguments[1]:void 0;if("object"===Type(e)){if(arguments.length<2)var i="default";else t===String?i="string":t===Number&&(i="number");var r="function"==typeof self.Symbol&&"symbol"==typeof self.Symbol.toPrimitive?GetMethod(e,self.Symbol.toPrimitive):void 0;if(void 0!==r){var o=Call(r,e,[i]);if("object"!==Type(o))return o;throw new TypeError("Cannot convert exotic object to primitive.")}return"default"===i&&(i="number"),OrdinaryToPrimitive(e,i)}return e}function ToString(t){switch(Type(t)){case"symbol":throw new TypeError("Cannot convert a Symbol value to a string");case"object":return ToString(ToPrimitive(t,String));default:return String(t)}}function ToPropertyKey(r){var i=ToPrimitive(r,String);return"symbol"===Type(i)?i:ToString(i)}function TrimString(e,u){var r=RequireObjectCoercible(e),t=ToString(r),n=/[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/.source;if("start"===u)var p=String.prototype.replace.call(t,new RegExp("^"+n,"g"),"");else p="end"===u?String.prototype.replace.call(t,new RegExp(n+"$","g"),""):String.prototype.replace.call(t,new RegExp("^"+n+"|"+n+"$","g"),"");return p}function UTF16Decode(e,n){return 1024*(e-55296)+(n-56320)+65536}CreateMethodProperty(Array.prototype,"includes",function e(r){"use strict";var t=ToObject(this),o=ToLength(Get(t,"length"));if(0===o)return!1;var n=ToInteger(arguments[1]);if(n>=0)var a=n;else(a=o+n)<0&&(a=0);for(;a<o;){var i=Get(t,ToString(a));if(SameValueZero(r,i))return!0;a+=1}return!1});"use strict";var origSort=Array.prototype.sort;CreateMethodProperty(Array.prototype,"sort",function r(t){if(void 0!==t&&!1===IsCallable(t))throw new TypeError("The comparison function must be either a function or undefined");if(void 0===t)origSort.call(this);else{var e=Array.prototype.map.call(this,function(r,t){return{item:r,index:t}});origSort.call(e,function(r,e){var o=t.call(void 0,r.item,e.item);return 0===o?r.index-e.index:o});for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&e[o].item!==this[o]&&(this[o]=e[o].item)}return this});CreateMethodProperty(Number,"isInteger",function e(r){return"number"===Type(r)&&(!isNaN(r)&&r!==1/0&&r!==-1/0&&ToInteger(r)===r)});Object.defineProperty(Number,"MAX_SAFE_INTEGER",{enumerable:!1,configurable:!1,writable:!1,value:Math.pow(2,53)-1});!function(){var t=Object.getOwnPropertyDescriptor,r={}.toString,e="".split;CreateMethodProperty(Object,"getOwnPropertyDescriptor",function o(n,c){var i=ToObject(n);i=("string"===Type(i)||i instanceof String)&&"[object String]"==r.call(n)?e.call(n,""):Object(n);var p=ToPropertyKey(c);return t(i,p)})}();!function(e){CreateMethodProperty(Object,"isExtensible",function t(n){return"object"===Type(n)&&(!e||e(n))})}(Object.isExtensible);CreateMethodProperty(Object,"keys",function(){"use strict";function t(){var t;try{t=Object.create({})}catch(t){return!0}return o.call(t,"__proto__")}function r(t){var r=n.call(t),e="[object Arguments]"===r;return e||(e="[object Array]"!==r&&null!==t&&"object"==typeof t&&"number"==typeof t.length&&t.length>=0&&"[object Function]"===n.call(t.callee)),e}var e=Object.prototype.hasOwnProperty,n=Object.prototype.toString,o=Object.prototype.propertyIsEnumerable,c=!o.call({toString:null},"toString"),l=o.call(function(){},"prototype"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],u=function(t){var r=t.constructor;return r&&r.prototype===t},a={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},f=function(){if("undefined"==typeof window)return!1;for(var t in window)try{if(!a["$"+t]&&e.call(window,t)&&null!==window[t]&&"object"==typeof window[t])try{u(window[t])}catch(t){return!0}}catch(t){return!0}return!1}(),p=function(t){if("undefined"==typeof window||!f)return u(t);try{return u(t)}catch(t){return!1}};return function o(u){var a="[object Function]"===n.call(u),f=r(u),s="[object String]"===n.call(u),y=[];if(void 0===u||null===u)throw new TypeError("Cannot convert undefined or null to object");var h=l&&a;if(s&&u.length>0&&!e.call(u,0))for(var g=0;g<u.length;++g)y.push(String(g));if(f&&u.length>0)for(var w=0;w<u.length;++w)y.push(String(w));else for(var $ in u)t()&&"__proto__"===$||h&&"prototype"===$||!e.call(u,$)||y.push(String($));if(c)for(var d=p(u),b=0;b<i.length;++b)d&&"constructor"===i[b]||!e.call(u,i[b])||y.push(i[b]);return y}}());function EnumerableOwnProperties(e,r){for(var t=Object.keys(e),n=[],s=t.length,a=0;a<s;a++){var i=t[a];if("string"===Type(i)){var u=Object.getOwnPropertyDescriptor(e,i);if(u&&u.enumerable)if("key"===r)n.push(i);else{var p=Get(e,i);if("value"===r)n.push(p);else{var f=[i,p];n.push(f)}}}}return n}!function(){var e={}.toString,t="".split;CreateMethodProperty(Object,"entries",function r(n){var i=ToObject(n);return i=("string"===Type(i)||i instanceof String)&&"[object String]"==e.call(n)?t.call(n,""):Object(n),EnumerableOwnProperties(i,"key+value")})}();CreateMethodProperty(Object,"assign",function t(e,r){var o=ToObject(e);if(1===arguments.length)return o;var c,a,l,n,i=Array.prototype.slice.call(arguments,1);for(c=0;c<i.length;c++){var p=i[c];for(void 0===p||null===p?l=[]:(n="[object String]"===Object.prototype.toString.call(p)?String(p).split(""):ToObject(p),l=Object.keys(n)),a=0;a<l.length;a++){var b,y=l[a];try{var g=Object.getOwnPropertyDescriptor(n,y);b=void 0!==g&&!0===g.enumerable}catch(t){b=Object.prototype.propertyIsEnumerable.call(n,y)}if(b){var j=Get(n,y);o[y]=j}}}return o});!function(){var t={}.toString,e="".split,r=[].concat,o=Object.prototype.hasOwnProperty,c=Object.getOwnPropertyNames||Object.keys,n="object"==typeof self?c(self):[];CreateMethodProperty(Object,"getOwnPropertyNames",function l(a){var p=ToObject(a);if("[object Window]"===t.call(p))try{return c(p)}catch(t){return r.call([],n)}p="[object String]"==t.call(p)?e.call(p,""):Object(p);for(var i=c(p),s=["length","prototype"],O=0;O<s.length;O++){var b=s[O];o.call(p,b)&&!i.includes(b)&&i.push(b)}if(i.includes("__proto__")){var f=i.indexOf("__proto__");i.splice(f,1)}return i})}();!function(){if(!Object.setPrototypeOf){var t,e,o=Object.getOwnPropertyNames,r=Object.getOwnPropertyDescriptor,n=Object.create,c=Object.defineProperty,_=Object.getPrototypeOf,f=Object.prototype,p=function(t,e){return o(e).forEach(function(o){c(t,o,r(e,o))}),t},O=function t(e,o){return p(n(o),e)};try{t=r(f,"__proto__").set,t.call({},null),e=function e(o,r){return t.call(o,r),o}}catch(o){t={__proto__:null},t instanceof Object?e=O:(t.__proto__=f,e=t instanceof Object?function t(e,o){return e.__proto__=o,e}:function t(e,o){return _(e)?(e.__proto__=o,e):O(e,o)})}CreateMethodProperty(Object,"setPrototypeOf",e)}}();!function(){var t={}.toString,e="".split;CreateMethodProperty(Object,"values",function r(n){var c="[object String]"==t.call(n)?e.call(n,""):ToObject(n);return Object.keys(c).map(function(t){return c[t]})})}();Object.defineProperty(RegExp.prototype,"flags",{configurable:!0,enumerable:!1,get:function(){var e=this;if("object"!==Type(e))throw new TypeError("Method called on incompatible type: must be an object.");var o="";return ToBoolean(Get(e,"global"))&&(o+="g"),ToBoolean(Get(e,"ignoreCase"))&&(o+="i"),ToBoolean(Get(e,"multiline"))&&(o+="m"),ToBoolean(Get(e,"unicode"))&&(o+="u"),ToBoolean(Get(e,"sticky"))&&(o+="y"),o}});CreateMethodProperty(String.prototype,"codePointAt",function t(e){var r=RequireObjectCoercible(this),o=ToString(r),i=ToInteger(e),n=o.length;if(!(i<0||i>=n)){var c=String.prototype.charCodeAt.call(o,i);if(c<55296||c>56319||i+1===n)return c;var a=String.prototype.charCodeAt.call(o,i+1);return a<56320||a>57343?c:UTF16Decode(c,a)}});function AdvanceStringIndex(e,n,t){if(n>Number.MAX_SAFE_INTEGER)throw new TypeError("Assertion failed: `index` must be <= 2**53");return!1===t?n+1:n+1>=e.length?n+1:n+e.codePointAt(n).length}CreateMethodProperty(String.prototype,"includes",function t(e){"use strict";var r=arguments.length>1?arguments[1]:void 0,n=RequireObjectCoercible(this),o=ToString(n);if(IsRegExp(e))throw new TypeError("First argument to String.prototype.includes must not be a regular expression");var i=ToString(e),g=ToInteger(r),a=o.length,p=Math.min(Math.max(g,0),a);return-1!==String.prototype.indexOf.call(o,i,p)});CreateMethodProperty(String.prototype,"repeat",function r(e){"use strict";var t=RequireObjectCoercible(this),n=ToString(t),o=ToInteger(e);if(o<0)throw new RangeError("Invalid count value");if(o===1/0)throw new RangeError("Invalid count value");return 0===o?"":new Array(o+1).join(n)});CreateMethodProperty(String.prototype,"trim",function t(){"use strict";var r=this;return TrimString(r,"start+end")});!function(r,t){var e=function t(e){var a=String(e).trim(),o=r(a);return 0===o&&"-"==a.charAt(0)?-0:o};CreateMethodProperty(t,"parseFloat",e),CreateMethodProperty(Number,"parseFloat",t.parseFloat)}(parseFloat,this);!function(t,r){var e=function r(e,n){var a=String(e).trim();return t(a,n>>>0||(/^[-+]?0[xX]/.test(a)?16:10))};CreateMethodProperty(r,"parseInt",e),CreateMethodProperty(Number,"parseInt",r.parseInt)}(parseInt,this);CreateMethodProperty(String.prototype,"trimEnd",function t(){"use strict";var r=this;return TrimString(r,"end")});CreateMethodProperty(String.prototype,"trimStart",function t(){"use strict";var r=this;return TrimString(r,"start")});!function(r,t,n){"use strict";function e(r){if("symbol"===Type(r))return r;throw TypeError(r+" is not a symbol")}var o,u=0,i=""+Math.random(),a="__symbol:",l=a.length,c="__symbol@@"+i,f={},s="defineProperty",v="defineProperties",y="getOwnPropertyNames",b="getOwnPropertyDescriptor",h="propertyIsEnumerable",p=r.prototype,m=p.hasOwnProperty,g=p[h],d=p.toString,w=Array.prototype.concat,S=r.getOwnPropertyNames?r.getOwnPropertyNames(self):[],P=r[y],O=function r(t){if("[object Window]"===d.call(t))try{return P(t)}catch(r){return w.call([],S)}return P(t)},j=r[b],E=r.create,N=r.keys,T=r.freeze||r,_=r[s],k=r[v],F=j(r,y),I=function(r,t,n){if(!m.call(r,c))try{_(r,c,{enumerable:!1,configurable:!1,writable:!1,value:{}})}catch(t){r[c]={}}r[c]["@@"+t]=n},x=function(r,t){var n=E(r);return O(t).forEach(function(r){W.call(t,r)&&K(n,r,t[r])}),n},z=function(r){var t=E(r);return t.enumerable=!1,t},A=function r(){},D=function(r){return r!=c&&!m.call(G,r)},M=function(r){return r!=c&&m.call(G,r)},W=function r(t){var n=""+t;return M(n)?m.call(this,n)&&this[c]&&this[c]["@@"+n]:g.call(this,t)},q=function(t){var n={enumerable:!1,configurable:!0,get:A,set:function(r){o(this,t,{enumerable:!1,configurable:!0,writable:!0,value:r}),I(this,t,!0)}};try{_(p,t,n)}catch(r){p[t]=n.value}G[t]=_(r(t),"constructor",H);var e=j(C.prototype,"description");return e&&_(G[t],"description",e),T(G[t])},B=function(r){var t=e(r);if(X){var n=U(t);if(""!==n)return n.slice(1,-1)}if(void 0!==f[t])return f[t];var o=t.toString(),u=o.lastIndexOf("0.");return""!==(o=o.slice(10,u))?o:void 0},C=function r(){var t=arguments[0];if(this instanceof r)throw new TypeError("Symbol is not a constructor");var n=a.concat(t||"",i,++u);return void 0===t||null!==t&&!isNaN(t)&&""!==String(t)||(f[n]=String(t)),q(n)},G=E(null),H={value:C},J=function(r){return G[r]},K=function r(t,n,e){var u=""+n;return M(u)?(o(t,u,e.enumerable?z(e):e),I(t,u,!!e.enumerable)):_(t,n,e),t},L=function(r){return function(t){return m.call(r,c)&&m.call(r[c],"@@"+t)}},Q=function r(t){return O(t).filter(t===p?L(t):M).map(J)};F.value=K,_(r,s,F),F.value=Q,_(r,"getOwnPropertySymbols",F),F.value=function r(t){return O(t).filter(D)},_(r,y,F),F.value=function r(t,n){var e=Q(n);return e.length?N(n).concat(e).forEach(function(r){W.call(n,r)&&K(t,r,n[r])}):k(t,n),t},_(r,v,F),F.value=W,_(p,h,F),F.value=C,_(n,"Symbol",F),F.value=function(r){var t=a.concat(a,r,i);return t in p?G[t]:q(t)},_(C,"for",F),F.value=function(r){if(D(r))throw new TypeError(r+" is not a symbol");return m.call(G,r)?r.slice(2*l,-i.length):void 0},_(C,"keyFor",F),F.value=function r(t,n){var e=j(t,n);return e&&M(n)&&(e.enumerable=W.call(t,n)),e},_(r,b,F),F.value=function r(t,n){return 1===arguments.length||void 0===n?E(t):x(t,n)},_(r,"create",F);var R=null===function(){return this}.call(null);if(F.value=R?function(){var r=d.call(this);return"[object String]"===r&&M(this)?"[object Symbol]":r}:function(){if(this===window)return"[object Null]";var r=d.call(this);return"[object String]"===r&&M(this)?"[object Symbol]":r},_(p,"toString",F),o=function(r,t,n){var e=j(p,t);delete p[t],_(r,t,n),r!==p&&_(p,t,e)},function(){try{var t={};return r.defineProperty(t,"t",{configurable:!0,enumerable:!1,get:function(){return!0},set:void 0}),!!t.t}catch(r){return!1}}()){var U;try{U=Function("s","var v = s.valueOf(); return { [v]() {} }[v].name;")}catch(r){}var V=function(){},X=U&&"inferred"===V.name?U:null;r.defineProperty(n.Symbol.prototype,"description",{configurable:!0,enumerable:!1,get:function(){return B(this)}})}}(Object,0,self);Object.defineProperty(self.Symbol,"iterator",{value:self.Symbol("iterator")});function GetIterator(t){var e=arguments.length>1?arguments[1]:GetMethod(t,Symbol.iterator),r=Call(e,t);if("object"!==Type(r))throw new TypeError("bad iterator");var o=GetV(r,"next"),a=Object.create(null);return a["[[Iterator]]"]=r,a["[[NextMethod]]"]=o,a["[[Done]]"]=!1,a}Object.defineProperty(Symbol,"matchAll",{value:Symbol("matchAll")});Object.defineProperty(Symbol,"replace",{value:Symbol("replace")});CreateMethodProperty(String.prototype,"replaceAll",function e(r,t){"use strict";var i=RequireObjectCoercible(this);if(void 0!==r&&null!==r){if(IsRegExp(r)){var o=Get(r,"flags");if(!("flags"in RegExp.prototype||!0===r.global))throw TypeError("");if("flags"in RegExp.prototype&&(RequireObjectCoercible(o),-1===ToString(o).indexOf("g")))throw TypeError("")}var l="Symbol"in self&&"replace"in self.Symbol?GetMethod(r,self.Symbol.replace):void 0;if(void 0!==l)return Call(l,r,[i,t])}var n=ToString(i),a=ToString(r),g=IsCallable(t);!1===g&&(t=ToString(t));for(var f=a.length,s=Math.max(1,f),p=[],v=StringIndexOf(n,a,0);-1!==v;)p.push(v),v=StringIndexOf(n,a,v+s);for(var b=0,u="",S=0;S<p.length;S++){var d=n.substring(b,p[S]);if(g)var h=ToString(Call(t,void 0,[a,p[S],n]));else{var c=[];h=GetSubstitution(a,n,p[S],c,void 0,t)}u=u+d+h,b=p[S]+f}return b<n.length&&(u+=n.substring(b)),u});Object.defineProperty(Symbol,"species",{value:Symbol("species")});!function(e){function t(e,t){if("object"!==Type(e))throw new TypeError("createMapIterator called on incompatible receiver "+Object.prototype.toString.call(e));if(!0!==e._es6Map)throw new TypeError("createMapIterator called on incompatible receiver "+Object.prototype.toString.call(e));var r=Object.create(y);return Object.defineProperty(r,"[[Map]]",{configurable:!0,enumerable:!1,writable:!0,value:e}),Object.defineProperty(r,"[[MapNextIndex]]",{configurable:!0,enumerable:!1,writable:!0,value:0}),Object.defineProperty(r,"[[MapIterationKind]]",{configurable:!0,enumerable:!1,writable:!0,value:t}),r}var r=0,o=Symbol("meta_"+(1e8*Math.random()+"").replace(".","")),a=function(e){if("object"==typeof e?null!==e:"function"==typeof e){if(!Object.isExtensible(e))return!1;if(!Object.prototype.hasOwnProperty.call(e,o)){var t=typeof e+"-"+ ++r;Object.defineProperty(e,o,{configurable:!1,enumerable:!1,writable:!1,value:t})}return e[o]}return""+e},p=function(e,t){var r=a(t);if(!1===r)return i(e,t);var o=e._table[r];return void 0!==o&&o},i=function(e,t){for(var r=0;r<e._keys.length;r++){var o=e._keys[r];if(o!==l&&SameValueZero(o,t))return r}return!1},n=function(e,t,r){var o=a(t);return!1!==o&&(!1===r?delete e._table[o]:e._table[o]=r,!0)},l=Symbol("undef"),c=function e(){if(!(this instanceof e))throw new TypeError('Constructor Map requires "new"');var t=OrdinaryCreateFromConstructor(this,e.prototype,{_table:{},_keys:[],_values:[],_size:0,_es6Map:!0}),r=arguments.length>0?arguments[0]:void 0;if(null===r||void 0===r)return t;var o=t.set;if(!IsCallable(o))throw new TypeError("Map.prototype.set is not a function");try{for(var a=GetIterator(r);;){var p=IteratorStep(a);if(!1===p)return t;var i=IteratorValue(p);if("object"!==Type(i))try{throw new TypeError("Iterator value "+i+" is not an entry object")}catch(e){return IteratorClose(a,e)}try{var n=i[0],l=i[1];o.call(t,n,l)}catch(e){return IteratorClose(a,e)}}}catch(e){if(Array.isArray(r)||"[object Arguments]"===Object.prototype.toString.call(r)){var c,y=r.length;for(c=0;c<y;c++)o.call(t,r[c][0],r[c][1])}}return t};Object.defineProperty(c,"prototype",{configurable:!1,enumerable:!1,writable:!1,value:{}}),Object.defineProperty(c,Symbol.species,{configurable:!0,enumerable:!1,get:function(){return this},set:void 0}),CreateMethodProperty(c.prototype,"clear",function e(){var t=this;if("object"!==Type(t))throw new TypeError("Method Map.prototype.clear called on incompatible receiver "+Object.prototype.toString.call(t));if(!0!==t._es6Map)throw new TypeError("Method Map.prototype.clear called on incompatible receiver "+Object.prototype.toString.call(t));for(var r=t._keys,o=0;o<r.length;o++)t._keys[o]=l,t._values[o]=l;this._size=0,this._table={}}),CreateMethodProperty(c.prototype,"constructor",c),CreateMethodProperty(c.prototype,"delete",function(e){var t=this;if("object"!==Type(t))throw new TypeError("Method Map.prototype.clear called on incompatible receiver "+Object.prototype.toString.call(t));if(!0!==t._es6Map)throw new TypeError("Method Map.prototype.clear called on incompatible receiver "+Object.prototype.toString.call(t));var r=p(t,e);if(!1!==r){var o=t._keys[r];if(o!==l&&SameValueZero(o,e))return this._keys[r]=l,this._values[r]=l,this._size=--this._size,n(this,e,!1),!0}return!1}),CreateMethodProperty(c.prototype,"entries",function e(){return t(this,"key+value")}),CreateMethodProperty(c.prototype,"forEach",function(e){var t=this;if("object"!==Type(t))throw new TypeError("Method Map.prototype.forEach called on incompatible receiver "+Object.prototype.toString.call(t));if(!0!==t._es6Map)throw new TypeError("Method Map.prototype.forEach called on incompatible receiver "+Object.prototype.toString.call(t));if(!IsCallable(e))throw new TypeError(Object.prototype.toString.call(e)+" is not a function.");if(arguments[1])var r=arguments[1];for(var o=t._keys,a=0;a<o.length;a++)t._keys[a]!==l&&t._values[a]!==l&&e.call(r,t._values[a],t._keys[a],t)}),CreateMethodProperty(c.prototype,"get",function e(t){var r=this;if("object"!==Type(r))throw new TypeError("Method Map.prototype.get called on incompatible receiver "+Object.prototype.toString.call(r));if(!0!==r._es6Map)throw new TypeError("Method Map.prototype.get called on incompatible receiver "+Object.prototype.toString.call(r));var o=p(r,t);if(!1!==o){var a=r._keys[o];if(a!==l&&SameValueZero(a,t))return r._values[o]}}),CreateMethodProperty(c.prototype,"has",function e(t){var r=this;if("object"!=typeof r)throw new TypeError("Method Map.prototype.has called on incompatible receiver "+Object.prototype.toString.call(r));if(!0!==r._es6Map)throw new TypeError("Method Map.prototype.has called on incompatible receiver "+Object.prototype.toString.call(r));var o=p(r,t);if(!1!==o){var a=r._keys[o];if(a!==l&&SameValueZero(a,t))return!0}return!1}),CreateMethodProperty(c.prototype,"keys",function e(){return t(this,"key")}),CreateMethodProperty(c.prototype,"set",function e(t,r){var o=this;if("object"!==Type(o))throw new TypeError("Method Map.prototype.set called on incompatible receiver "+Object.prototype.toString.call(o));if(!0!==o._es6Map)throw new TypeError("Method Map.prototype.set called on incompatible receiver "+Object.prototype.toString.call(o));var a=p(o,t);if(!1!==a)o._values[a]=r;else{-0===t&&(t=0);var i={"[[Key]]":t,"[[Value]]":r};o._keys.push(i["[[Key]]"]),o._values.push(i["[[Value]]"]),n(o,t,o._keys.length-1),++o._size}return o}),Object.defineProperty(c.prototype,"size",{configurable:!0,enumerable:!1,get:function(){var e=this;if("object"!==Type(e))throw new TypeError("Method Map.prototype.size called on incompatible receiver "+Object.prototype.toString.call(e));if(!0!==e._es6Map)throw new TypeError("Method Map.prototype.size called on incompatible receiver "+Object.prototype.toString.call(e));return this._size},set:void 0}),CreateMethodProperty(c.prototype,"values",function e(){return t(this,"value")}),CreateMethodProperty(c.prototype,Symbol.iterator,c.prototype.entries),"name"in c||Object.defineProperty(c,"name",{configurable:!0,enumerable:!1,writable:!1,value:"Map"});var y={};Object.defineProperty(y,"isMapIterator",{configurable:!1,enumerable:!1,writable:!1,value:!0}),CreateMethodProperty(y,"next",function e(){var t=this;if("object"!==Type(t))throw new TypeError("Method %MapIteratorPrototype%.next called on incompatible receiver "+Object.prototype.toString.call(t));if(!t.isMapIterator)throw new TypeError("Method %MapIteratorPrototype%.next called on incompatible receiver "+Object.prototype.toString.call(t));var r=t["[[Map]]"],o=t["[[MapNextIndex]]"],a=t["[[MapIterationKind]]"];if(void 0===r)return CreateIterResultObject(void 0,!0);if(!r._es6Map)throw new Error(Object.prototype.toString.call(r)+" has a [[MapData]] internal slot.");for(var p=r._keys,i=p.length;o<i;){var n=Object.create(null);if(n["[[Key]]"]=r._keys[o],n["[[Value]]"]=r._values[o],o+=1,t["[[MapNextIndex]]"]=o,n["[[Key]]"]!==l){if("key"===a)var c=n["[[Key]]"];else if("value"===a)c=n["[[Value]]"];else{if("key+value"!==a)throw new Error;c=[n["[[Key]]"],n["[[Value]]"]]}return CreateIterResultObject(c,!1)}}return t["[[Map]]"]=void 0,CreateIterResultObject(void 0,!0)}),CreateMethodProperty(y,Symbol.iterator,function e(){return this}),CreateMethodProperty(e,"Map",c)}(self);!function(e){function t(e,t){if("object"!=typeof e)throw new TypeError("createSetIterator called on incompatible receiver "+Object.prototype.toString.call(e));if(!0!==e._es6Set)throw new TypeError("createSetIterator called on incompatible receiver "+Object.prototype.toString.call(e));var r=Object.create(i);return Object.defineProperty(r,"[[IteratedSet]]",{configurable:!0,enumerable:!1,writable:!0,value:e}),Object.defineProperty(r,"[[SetNextIndex]]",{configurable:!0,enumerable:!1,writable:!0,value:0}),Object.defineProperty(r,"[[SetIterationKind]]",{configurable:!0,enumerable:!1,writable:!0,value:t}),r}var r=Symbol("undef"),o=function e(){if(!(this instanceof e))throw new TypeError('Constructor Set requires "new"');var t=OrdinaryCreateFromConstructor(this,e.prototype,{_values:[],_size:0,_es6Set:!0}),r=arguments.length>0?arguments[0]:void 0;if(null===r||void 0===r)return t;var o=t.add;if(!IsCallable(o))throw new TypeError("Set.prototype.add is not a function");try{for(var a=GetIterator(r);;){var i=IteratorStep(a);if(!1===i)return t;var n=IteratorValue(i);try{o.call(t,n)}catch(e){return IteratorClose(a,e)}}}catch(e){if(!Array.isArray(r)&&"[object Arguments]"!==Object.prototype.toString.call(r))throw e;var l,p=r.length;for(l=0;l<p;l++)o.call(t,r[l])}return t};Object.defineProperty(o,"prototype",{configurable:!1,enumerable:!1,writable:!1,value:{}}),Object.defineProperty(o,Symbol.species,{configurable:!0,enumerable:!1,get:function(){return this},set:void 0}),CreateMethodProperty(o.prototype,"add",function e(t){var o=this;if("object"!=typeof o)throw new TypeError("Method Set.prototype.add called on incompatible receiver "+Object.prototype.toString.call(o));if(!0!==o._es6Set)throw new TypeError("Method Set.prototype.add called on incompatible receiver "+Object.prototype.toString.call(o));for(var a=o._values,i=0;i<a.length;i++){var n=a[i];if(n!==r&&SameValueZero(n,t))return o}return 0===t&&1/t==-1/0&&(t=0),o._values.push(t),this._size=++this._size,o}),CreateMethodProperty(o.prototype,"clear",function e(){var t=this;if("object"!=typeof t)throw new TypeError("Method Set.prototype.clear called on incompatible receiver "+Object.prototype.toString.call(t));if(!0!==t._es6Set)throw new TypeError("Method Set.prototype.clear called on incompatible receiver "+Object.prototype.toString.call(t));for(var o=t._values,a=0;a<o.length;a++)o[a]=r;this._size=0}),CreateMethodProperty(o.prototype,"constructor",o),CreateMethodProperty(o.prototype,"delete",function(e){var t=this;if("object"!=typeof t)throw new TypeError("Method Set.prototype.delete called on incompatible receiver "+Object.prototype.toString.call(t));if(!0!==t._es6Set)throw new TypeError("Method Set.prototype.delete called on incompatible receiver "+Object.prototype.toString.call(t));for(var o=t._values,a=0;a<o.length;a++){var i=o[a];if(i!==r&&SameValueZero(i,e))return o[a]=r,this._size=--this._size,!0}return!1}),CreateMethodProperty(o.prototype,"entries",function e(){return t(this,"key+value")}),CreateMethodProperty(o.prototype,"forEach",function e(t){var o=this;if("object"!=typeof o)throw new TypeError("Method Set.prototype.forEach called on incompatible receiver "+Object.prototype.toString.call(o));if(!0!==o._es6Set)throw new TypeError("Method Set.prototype.forEach called on incompatible receiver "+Object.prototype.toString.call(o));if(!IsCallable(t))throw new TypeError(Object.prototype.toString.call(t)+" is not a function.");if(arguments[1])var a=arguments[1];for(var i=o._values,n=0;n<i.length;n++){var l=i[n];l!==r&&t.call(a,l,l,o)}}),CreateMethodProperty(o.prototype,"has",function e(t){var o=this;if("object"!=typeof o)throw new TypeError("Method Set.prototype.forEach called on incompatible receiver "+Object.prototype.toString.call(o));if(!0!==o._es6Set)throw new TypeError("Method Set.prototype.forEach called on incompatible receiver "+Object.prototype.toString.call(o));for(var a=o._values,i=0;i<a.length;i++){var n=a[i];if(n!==r&&SameValueZero(n,t))return!0}return!1});var a=function e(){return t(this,"value")};CreateMethodProperty(o.prototype,"values",a),CreateMethodProperty(o.prototype,"keys",a),Object.defineProperty(o.prototype,"size",{configurable:!0,enumerable:!1,get:function(){var e=this;if("object"!=typeof e)throw new TypeError("Method Set.prototype.size called on incompatible receiver "+Object.prototype.toString.call(e));if(!0!==e._es6Set)throw new TypeError("Method Set.prototype.size called on incompatible receiver "+Object.prototype.toString.call(e));for(var t=e._values,o=0,a=0;a<t.length;a++){t[a]!==r&&(o+=1)}return o},set:void 0}),CreateMethodProperty(o.prototype,Symbol.iterator,a),"name"in o||Object.defineProperty(o,"name",{configurable:!0,enumerable:!1,writable:!1,value:"Set"});var i={};Object.defineProperty(i,"isSetIterator",{configurable:!1,enumerable:!1,writable:!1,value:!0}),CreateMethodProperty(i,"next",function e(){var t=this;if("object"!=typeof t)throw new TypeError("Method %SetIteratorPrototype%.next called on incompatible receiver "+Object.prototype.toString.call(t));if(!t.isSetIterator)throw new TypeError("Method %SetIteratorPrototype%.next called on incompatible receiver "+Object.prototype.toString.call(t));var o=t["[[IteratedSet]]"],a=t["[[SetNextIndex]]"],i=t["[[SetIterationKind]]"];if(void 0===o)return CreateIterResultObject(void 0,!0);if(!o._es6Set)throw new Error(Object.prototype.toString.call(o)+" does not have [[SetData]] internal slot.");for(var n=o._values,l=n.length;a<l;){var p=n[a];if(a+=1,t["[[SetNextIndex]]"]=a,p!==r)return"key+value"===i?CreateIterResultObject([p,p],!1):CreateIterResultObject(p,!1)}return t["[[IteratedSet]]"]=void 0,CreateIterResultObject(void 0,!0)}),CreateMethodProperty(i,Symbol.iterator,function e(){return this}),CreateMethodProperty(e,"Set",o)}(self);!function(){function r(r){return"string"==typeof r||"object"==typeof r&&"[object String]"===t.call(r)}var t=Object.prototype.toString,e=String.prototype.match;CreateMethodProperty(Array,"from",function t(o){var a=this,n=arguments.length>1?arguments[1]:void 0;if(void 0===n)var i=!1;else{if(!1===IsCallable(n))throw new TypeError(Object.prototype.toString.call(n)+" is not a function.");var l=arguments.length>2?arguments[2]:void 0;if(void 0!==l)var c=l;else c=void 0;i=!0}var u=GetMethod(o,Symbol.iterator);if(void 0!==u){if(IsConstructor(a))var v=Construct(a);else v=ArrayCreate(0);for(var f=GetIterator(o,u),s=0;;){if(s>=Math.pow(2,53)-1){var h=new TypeError("Iteration count can not be greater than or equal 9007199254740991.");return IteratorClose(f,h)}var y=ToString(s),C=IteratorStep(f);if(!1===C)return v.length=s,v;var g=IteratorValue(C);if(i)try{var p=Call(n,c,[g,s])}catch(r){return IteratorClose(f,r)}else p=g;try{CreateDataPropertyOrThrow(v,y,p)}catch(r){return IteratorClose(f,r)}s+=1}}if(r(o))var I=e.call(o,/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[^\uD800-\uDFFF]|./g)||[];else I=ToObject(o);var b=ToLength(Get(I,"length"));for(v=IsConstructor(a)?Construct(a,[b]):ArrayCreate(b),s=0;s<b;){y=ToString(s);var d=Get(I,y);p=!0===i?Call(n,c,[d,s]):d,CreateDataPropertyOrThrow(v,y,p),s+=1}return v.length=b,v})}();Object.defineProperty(Symbol,"toStringTag",{value:Symbol("toStringTag")});function CreateRegExpStringIterator(e,t,r,n){var a={};return CreateMethodProperty(a,"next",function a(){if(!0===this["[[Done]]"])return CreateIterResultObject(void 0,!0);var i=RegExpExec(e,t);if(null===i)return this["[[Done]]"]=!0,CreateIterResultObject(void 0,!0);if(!1===r){var o=CreateIterResultObject(i,!1);return this["[[Done]]"]=!0,o}if(""===ToString(Get(i,"0"))){var u=ToLength(Get(e,"lastIndex")),l=AdvanceStringIndex(t,u,n);e.lastIndex=l}return CreateIterResultObject(i,!1)}),Object.defineProperty(a,Symbol.toStringTag,{configurable:!0,enumerable:!1,writable:!1,value:"RegExp String Iterator"}),CreateMethodProperty(a,Symbol.iterator,function e(){return this}),a}var supportsRegexpLiteralConstructorWithFlags=function(){try{return new RegExp(/x/,"g"),!0}catch(t){return!1}}();CreateMethodProperty(RegExp.prototype,Symbol.matchAll,function(t){"use strict";var e=this;if("object"!==Type(e))throw new TypeError("Method called on incompatible type: must be an object.");var r=ToString(t),o=SpeciesConstructor(e,RegExp),n=ToString(Get(e,"flags"));"flags"in RegExp.prototype||(n="",!0===e.global&&(n+="g"),!0===e.ignoreCase&&(n+="i"),!0===e.multiline&&(n+="m"));var a=Construct(o,[supportsRegexpLiteralConstructorWithFlags?e:e.source,n]),i=ToLength(Get(e,"lastIndex"));a.lastIndex=i;var p=n.indexOf("g")>-1,s=n.indexOf("u")>-1;return CreateRegExpStringIterator(a,r,p,s)});CreateMethodProperty(String.prototype,"matchAll",function e(l){"use strict";var r=RequireObjectCoercible(this);if(void 0!==l&&null!==l){if(IsRegExp(l)){var t=Get(l,"flags");if(!("flags"in RegExp.prototype||!0===l.global))throw TypeError("");if("flags"in RegExp.prototype&&(RequireObjectCoercible(t),-1===ToString(t).indexOf("g")))throw TypeError("")}var o="Symbol"in self&&"matchAll"in self.Symbol?GetMethod(l,self.Symbol.matchAll):void 0;if(void 0!==o)return Call(o,l,[r])}var i=ToString(r),n=new RegExp(l,"g");return Invoke(n,"Symbol"in self&&"matchAll"in self.Symbol&&self.Symbol.matchAll,[i])});var Iterator=function(){var e=function(){return this.length=0,this},t=function(e){if("function"!=typeof e)throw new TypeError(e+" is not a function");return e},_=function(e,n){if(!(this instanceof _))return new _(e,n);Object.defineProperties(this,{__list__:{writable:!0,value:e},__context__:{writable:!0,value:n},__nextIndex__:{writable:!0,value:0}}),n&&(t(n.on),n.on("_add",this._onAdd.bind(this)),n.on("_delete",this._onDelete.bind(this)),n.on("_clear",this._onClear.bind(this)))};return Object.defineProperties(_.prototype,Object.assign({constructor:{value:_,configurable:!0,enumerable:!1,writable:!0},_next:{value:function(){var e;if(this.__list__)return this.__redo__&&void 0!==(e=this.__redo__.shift())?e:this.__nextIndex__<this.__list__.length?this.__nextIndex__++:void this._unBind()},configurable:!0,enumerable:!1,writable:!0},next:{value:function(){return this._createResult(this._next())},configurable:!0,enumerable:!1,writable:!0},_createResult:{value:function(e){return void 0===e?{done:!0,value:void 0}:{done:!1,value:this._resolve(e)}},configurable:!0,enumerable:!1,writable:!0},_resolve:{value:function(e){return this.__list__[e]},configurable:!0,enumerable:!1,writable:!0},_unBind:{value:function(){this.__list__=null,delete this.__redo__,this.__context__&&(this.__context__.off("_add",this._onAdd.bind(this)),this.__context__.off("_delete",this._onDelete.bind(this)),this.__context__.off("_clear",this._onClear.bind(this)),this.__context__=null)},configurable:!0,enumerable:!1,writable:!0},toString:{value:function(){return"[object Iterator]"},configurable:!0,enumerable:!1,writable:!0}},{_onAdd:{value:function(e){if(!(e>=this.__nextIndex__)){if(++this.__nextIndex__,!this.__redo__)return void Object.defineProperty(this,"__redo__",{value:[e],configurable:!0,enumerable:!1,writable:!1});this.__redo__.forEach(function(t,_){t>=e&&(this.__redo__[_]=++t)},this),this.__redo__.push(e)}},configurable:!0,enumerable:!1,writable:!0},_onDelete:{value:function(e){var t;e>=this.__nextIndex__||(--this.__nextIndex__,this.__redo__&&(t=this.__redo__.indexOf(e),-1!==t&&this.__redo__.splice(t,1),this.__redo__.forEach(function(t,_){t>e&&(this.__redo__[_]=--t)},this)))},configurable:!0,enumerable:!1,writable:!0},_onClear:{value:function(){this.__redo__&&e.call(this.__redo__),this.__nextIndex__=0},configurable:!0,enumerable:!1,writable:!0}})),Object.defineProperty(_.prototype,Symbol.iterator,{value:function(){return this},configurable:!0,enumerable:!1,writable:!0}),Object.defineProperty(_.prototype,Symbol.toStringTag,{value:"Iterator",configurable:!1,enumerable:!1,writable:!0}),_}();var ArrayIterator=function(){var e=function(t,r){if(!(this instanceof e))return new e(t,r);Iterator.call(this,t),r=r?String.prototype.includes.call(r,"key+value")?"key+value":String.prototype.includes.call(r,"key")?"key":"value":"value",Object.defineProperty(this,"__kind__",{value:r,configurable:!1,enumerable:!1,writable:!1})};return Object.setPrototypeOf&&Object.setPrototypeOf(e,Iterator.prototype),e.prototype=Object.create(Iterator.prototype,{constructor:{value:e,configurable:!0,enumerable:!1,writable:!0},_resolve:{value:function(e){return"value"===this.__kind__?this.__list__[e]:"key+value"===this.__kind__?[e,this.__list__[e]]:e},configurable:!0,enumerable:!1,writable:!0},toString:{value:function(){return"[object Array Iterator]"},configurable:!0,enumerable:!1,writable:!0}}),e}();CreateMethodProperty(Array.prototype,"entries",function r(){var e=ToObject(this);return new ArrayIterator(e,"key+value")});!function(){"use strict";function n(){return tn[q][B]||D}function t(n){return n&&"object"==typeof n}function e(n){return"function"==typeof n}function r(n,t){return n instanceof t}function o(n){return r(n,A)}function i(n,t,e){if(!t(n))throw a(e)}function u(){try{return b.apply(R,arguments)}catch(n){return Y.e=n,Y}}function c(n,t){return b=n,R=t,u}function f(n,t){function e(){for(var e=0;e<o;)t(r[e],r[e+1]),r[e++]=T,r[e++]=T;o=0,r.length>n&&(r.length=n)}var r=L(n),o=0;return function(n,t){r[o++]=n,r[o++]=t,2===o&&tn.nextTick(e)}}function s(n,t){var o,i,u,f,s=0;if(!n)throw a(N);var l=n[tn[q][z]];if(e(l))i=l.call(n);else{if(!e(n.next)){if(r(n,L)){for(o=n.length;s<o;)t(n[s],s++);return s}throw a(N)}i=n}for(;!(u=i.next()).done;)if((f=c(t)(u.value,s++))===Y)throw e(i[G])&&i[G](),f.e;return s}function a(n){return new TypeError(n)}function l(n){return(n?"":Q)+(new A).stack}function h(n,t){var e="on"+n.toLowerCase(),r=F[e];E&&E.listeners(n).length?n===X?E.emit(n,t._v,t):E.emit(n,t):r?r({reason:t._v,promise:t}):tn[n](t._v,t)}function v(n){return n&&n._s}function _(n){if(v(n))return new n(Z);var t,r,o;return t=new n(function(n,e){if(t)throw a();r=n,o=e}),i(r,e),i(o,e),t}function d(n,t){var e=!1;return function(r){e||(e=!0,I&&(n[M]=l(!0)),t===U?g(n,r):y(n,t,r))}}function p(n,t,r,o){return e(r)&&(t._onFulfilled=r),e(o)&&(n[J]&&h(W,n),t._onRejected=o),I&&(t._p=n),n[n._c++]=t,n._s!==$&&rn(n,t),t}function m(n){if(n._umark)return!0;n._umark=!0;for(var t,e=0,r=n._c;e<r;)if(t=n[e++],t._onRejected||m(t))return!0}function w(n,t){function e(n){return r.push(n.replace(/^\s+|\s+$/g,""))}var r=[];return I&&(t[M]&&e(t[M]),function n(t){t&&K in t&&(n(t._next),e(t[K]+""),n(t._p))}(t)),(n&&n.stack?n.stack:n)+("\n"+r.join("\n")).replace(nn,"")}function j(n,t){return n(t)}function y(n,t,e){var r=0,i=n._c;if(n._s===$)for(n._s=t,n._v=e,t===O&&(I&&o(e)&&(e.longStack=w(e,n)),on(n));r<i;)rn(n,n[r++]);return n}function g(n,r){if(r===n&&r)return y(n,O,a(V)),n;if(r!==S&&(e(r)||t(r))){var o=c(k)(r);if(o===Y)return y(n,O,o.e),n;e(o)?(I&&v(r)&&(n._next=r),v(r)?x(n,r,o):tn.nextTick(function(){x(n,r,o)})):y(n,U,r)}else y(n,U,r);return n}function k(n){return n.then}function x(n,t,e){var r=c(e,t)(function(e){t&&(t=S,g(n,e))},function(e){t&&(t=S,y(n,O,e))});r===Y&&t&&(y(n,O,r.e),t=S)}var T,b,R,S=null,C="object"==typeof self,F=self,P=F.Promise,E=F.process,H=F.console,I=!0,L=Array,A=Error,O=1,U=2,$=3,q="Symbol",z="iterator",B="species",D=q+"("+B+")",G="return",J="_uh",K="_pt",M="_st",N="Invalid argument",Q="\nFrom previous ",V="Chaining cycle detected for promise",W="rejectionHandled",X="unhandledRejection",Y={e:S},Z=function(){},nn=/^.+\/node_modules\/yaku\/.+\n?/gm,tn=function(n){var r,o=this;if(!t(o)||o._s!==T)throw a("Invalid this");if(o._s=$,I&&(o[K]=l()),n!==Z){if(!e(n))throw a(N);r=c(n)(d(o,U),d(o,O)),r===Y&&y(o,O,r.e)}};tn.default=tn,function en(n,t){for(var e in t)n[e]=t[e]}(tn.prototype,{then:function(n,t){if(void 0===this._s)throw a();return p(this,_(tn.speciesConstructor(this,tn)),n,t)},catch:function(n){return this.then(T,n)},finally:function(n){return this.then(function(t){return tn.resolve(n()).then(function(){return t})},function(t){return tn.resolve(n()).then(function(){throw t})})},_c:0,_p:S}),tn.resolve=function(n){return v(n)?n:g(_(this),n)},tn.reject=function(n){return y(_(this),O,n)},tn.race=function(n){var t=this,e=_(t),r=function(n){y(e,U,n)},o=function(n){y(e,O,n)},i=c(s)(n,function(n){t.resolve(n).then(r,o)});return i===Y?t.reject(i.e):e},tn.all=function(n){function t(n){y(o,O,n)}var e,r=this,o=_(r),i=[];return(e=c(s)(n,function(n,u){r.resolve(n).then(function(n){i[u]=n,--e||y(o,U,i)},t)}))===Y?r.reject(e.e):(e||y(o,U,[]),o)},tn.Symbol=F[q]||{},c(function(){Object.defineProperty(tn,n(),{get:function(){return this}})})(),tn.speciesConstructor=function(t,e){var r=t.constructor;return r?r[n()]||e:e},tn.unhandledRejection=function(n,t){H&&H.error("Uncaught (in promise)",I?t.longStack:w(n,t))},tn.rejectionHandled=Z,tn.enableLongStackTrace=function(){I=!0},tn.nextTick=C?function(n){P?new P(function(n){n()}).then(n):setTimeout(n)}:E.nextTick,tn._s=1;var rn=f(999,function(n,t){var e,r;return(r=n._s!==O?t._onFulfilled:t._onRejected)===T?void y(t,n._s,n._v):(e=c(j)(r,n._v))===Y?void y(t,O,e.e):void g(t,e)}),on=f(9,function(n){m(n)||(n[J]=1,h(X,n))});F.Promise=tn}();})('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
\ No newline at end of file
{"v":"5.6.10","fr":30,"ip":0,"op":25,"w":464,"h":464,"nm":"点击光晕","ddd":0,"assets":[{"id":"0","w":40,"h":36,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAkBAMAAAAJEmUlAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJFBMVEVHcEz///////////////////////////////////////////8Uel1nAAAADHRSTlMAAgYWDSEtPE5t3J8u7P32AAABLUlEQVQoz32S/XGDMAzF8Qa2N4DzBoYFwBtwZgPMBpAs0CYbpNcNyASU5fokDAHai/783ZP09JEk70IIcUZSURyxUCpFKHVgOqNI91qhssyYElTueoA550DVRoUmlufOocAKlTausgiiIibrDKz2HnQroFLjbOERNi8BJfvOTGV9E4Kv7VoVfiBswtAHb13J+VzS+jAMQ2hr5LNXgoUPl9uNpUsnKons69djgVwUzQG7+zx97iCUzXUex/E59XUOpyu8/wCO08cGNdK7y/c8P/p29fRfIylIuVhqX420JvPd0Xwcs8PwvBFWctHTQtCJpL6h1bm4urjkgpdcbldC/uscKokUUldVuOcyzuHEe8ZSNDP0DHL/XvFtTg8GptROSAvgV5R/PhQqKd989S8i62hSglkILgAAAABJRU5ErkJggg==","e":1},{"id":"1","w":40,"h":36,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAkBAMAAAAJEmUlAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJFBMVEVHcEz///////////////////////////////////////////8Uel1nAAAADHRSTlMABAsTHCc0TN5tq4+3c1CoAAABLElEQVQoz32S7W2EMAyGyQYOGxA2IGyA2QCzAckGoG6A2gFOpy5Q3Q1Qqbdc7YRAKFL988kb+/VHUfwboK6IGfzhoENAzpTSuhSqzkLDUeVS1lUCyzwB6NIYaxtjNMCesTS1bYVWuoBUhRlydIEGVvBnZkQDWoYqZaxbpNERYsMGVPqN/ejcRCyNpQRaJOcXR0OX/nPKloXLMk9D10QYUvajv99nR1w/+FcCafSv141LNSGpEtj7z691fX/Og01Kw/Bn5fi4DbE8iBLJvz0e3/OEec5YiI2Ke4gjantKlqKy0Jt5F8zH6cc26WjzNJCRsGu23qX8PjrpUm0rOoac9gFSn9eB1sqS1L442ZutcxZchcivIRyI3MKx4e0c9IWJNpzShcJJuD9dwSH7BXaDVTvBQtwXAAAAAElFTkSuQmCC","e":1},{"id":"2","w":3,"h":62,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAA+BAMAAAD+PqeGAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAHlBMVEX/ryH/qiX/qiT/qiT/qiP/qiP/qiT/qiT/qiP/qiT+my6IAAAACnRSTlMDDholL1R8aJBAe3LT/wAAAGpJREFUCNdjYAADRgUGZkMGFkcGkYkMIpMYJIEoCIpEIaiIQbUYhNQhKBmE1JIZzIAohcGsBYQswMgDFQFFzJrBasCK1cAaoYYAzQSiIBAShVg3EWz1RLAzHBmEgcgQ5DAmBRBiFAAhGAAAfJUd5q7Fp1UAAAAASUVORK5CYII=","e":1},{"id":"3","w":242,"h":227,"u":"","p":"data:image/png;base64,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","e":1},{"id":"4","w":251,"h":250,"u":"","p":"data:image/png;base64,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","e":1},{"id":"5","w":20,"h":50,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAyBAMAAACuUuYVAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAIVBMVEVHcEz//N7/663/6af/8cH/5qH/6LL/7rX/+Nb/6av//fS/VPvmAAAAC3RSTlMAA0s4aycMWoAXleZLH2UAAACuSURBVCjPbdI7C8IwEMDxuyWQLVncCxk6Wij0K4hTsUNXFwVHt+KnKIjf18vlcUEv049/X3kUgMbBQRm3a+Vlr1xnjZNwbHjUGFT2ldgPGjeNZuv+iZG8DgRzkkp0lBHBSrVcKTtvz090/FRiqV2phugRYmVKdfTSWF/pXp7DgPFzdIEIufLU09vi2koNuZLDnMUssxy1rcZm16ddO6yGi/AtB/sRPoR3+Qk8/IwvsV8dlZtoBVMAAAAASUVORK5CYII=","e":1},{"id":"6","w":3,"h":41,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAApBAMAAADg7ZWlAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJFBMVEX/tRf/qyX/qiP/qiT/qyT/qiT/qiT/qiT/qiT/qiT/qiT/qiQYBbxQAAAADHRSTlMBEAghLRh+OFhqlEYbz77OAAAAX0lEQVQI12NgYGBgFGJQdmRQKWVQ2cqgDkTNDNrNDNLNDBKTGSSmMEikMETCUNgSBrPlIGQFRhC22RKGMJiCiMlgXZNB2qVbwaZtZVApBJkPRKxGDIxBDExCDAwKQGsBZLIZVgs6k9MAAAAASUVORK5CYII=","e":1},{"id":"7","w":142,"h":4,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI4AAAAEBAMAAACq+BqFAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAKlBMVEX/rB3/qiT/qiP/qiT/qiP/qiT/qiT/qyT/qiT/qiP/qiP/qiT/qiT/qiSaS68eAAAADnRSTlMBCjIjPxRWS3eJZqTLuacbDhQAAACoSURBVBjTdc7BDYMgFAZg2EAOLmCdQOMChgWIYYXXxHNTVqAbSHonDRs0xA3aDdpd+j+0R78TvPD/PCGEqm0PXdewttWFgyvtcL7wsLxo+HU/TZYpEIW0nXZEKaWH9wHuOed1/cLn9ffmK+b5GcKyeJ9SpLPTI0oHa7Ymue+Dn/Y9iOa51PobFwcEOZpiJKSd1iMKTsgM20biSFVJqYq6ttYYU86YHiZ+c+1U9WT2vMYAAAAASUVORK5CYII=","e":1},{"id":"8","w":53,"h":138,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAACKBAMAAAD4VB/jAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAeUExURUdwTP/46//56v/45v/45//35P/35f/24//24f/13w2BpBIAAAAKdFJOUwAKFig8UmqFpMftbWYuAAACtElEQVRIx61X7XXbMAwUOgGhTiBqA9IbSNlA8gS1vYGcDaxsYG/bA22nCcVj+vLCv/fuAJD4YtN8/zj5FigiDWc6dRSyQ1VVGQiDqtSicqJTAytEAsJeq8p5bYXYtUojbKmq09ZrhUhBVe9p/HeQiLYcM17HvAHmKQbRzlUwLho9vRofAhMV31OitjEGZdHHGImotP0uehZFHwcmqv1uoKL9bhyoQWBE1LCRGWzjOMaOOTNOzCCweQzlrJGEodxcGYOoFGvx926eYbBQ4oIg5sMUinkKbH+cQqeyQVEUwCBaqH5JvMOAlMo7lVUvMIha1cgmm3b70zJFEHXTLYCdlySahy8JOx+GsEli9IPesGMSlTwJDbvAIEJ0mZse2Ou6/IHoxhffj8BgMOa1D14cj6/r5TDGrNpMM76cgBUM6h27rss05AVlOf9yWt/WZR4yHjQTdruezaCWeLdrcibjAZtPb4ZNOS9dC7AbHB2yAN+xNWG5PVzLAwufeHj1B3ZNQTjCA/bZz//iXX+OJxVe0jy/x+f4vXSSv8NsvMvR7iz3M73DrfAOX72fYWvp3VEONF9ay7P1kWfb3LX8XI8pP7e5uy/mdfOslUI9pDrChV7Mlc0s+FB/eR0pHP1Xt9sR+Kz3vG196BPbCZr6xOkumfGefWkMpWn+7Ge2zRR5aLxdYQt69Nau1FwNm+99dwv61K+10MwdhtU8xU4q86EpDYE0c0J5c/zVjxiAZI71fI7ZjKOzMWJukpmKHslmMZ4IyUfnO1saxDCyFzjkfOD7RGSrlu02ZH8R7DaeSvrA1x6+oKEaqGRlr5O0ujm2m1ZXPhK4069o1FzL7ksBkVVYteuoJ4axzdsk+feB/ErQWShNjMb+Ofy74ri1RKv9uYT+qlzlr1b5/gn9jLnKj1Kk+enDFf8CbzHuJ3K7ZXYAAAAASUVORK5CYII=","e":1}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"组 9","refId":"0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":11.509,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.38,"y":1},"o":{"x":0.224,"y":0},"t":0,"s":[211,230.815,0],"to":[28.178,0,0],"ti":[-28.178,0,0]},{"t":16,"s":[380.068,230.815,0]}],"ix":2},"a":{"a":0,"k":[20,18,0],"ix":1},"s":{"a":0,"k":[163,163,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"组 8","refId":"1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":11.509,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[211.19,230.815,0],"to":[-25.655,0,0],"ti":[25.655,0,0]},{"t":16,"s":[57.258,230.815,0]}],"ix":2},"a":{"a":0,"k":[20,18,0],"ix":1},"s":{"a":0,"k":[163,163,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"图层 8 拷贝 2","refId":"2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":8.785,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":12.08,"s":[100]},{"t":20.866,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[178.002,318.655,0],"to":[0,-5.5,0],"ti":[0,5.5,0]},{"t":18,"s":[178.002,285.655,0]}],"ix":2},"a":{"a":0,"k":[1.5,31,0],"ix":1},"s":{"a":0,"k":[163,163,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"571053203a2b4.png","cl":"png","refId":"3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4.847,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16.357,"s":[100]},{"t":21.384,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[231.287,232,0],"ix":2},"a":{"a":0,"k":[120.25,121.5,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.645,0.645,0.667],"y":[-13.335,0.857,1]},"o":{"x":[0.776,0.776,0.333],"y":[0,0,0]},"t":0,"s":[100,0,100]},{"i":{"x":[0.606,0.606,0.833],"y":[1,1,1]},"o":{"x":[0.124,0.124,0.167],"y":[0.175,0.175,0]},"t":9.334,"s":[100,100,100]},{"t":21.384,"s":[137,137,100]}],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":2,"nm":"组 10","refId":"4","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4.038,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17.345,"s":[100]},{"t":23,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[217.171,232.325,0],"ix":2},"a":{"a":0,"k":[125.653,123.006,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[0.876,0.876,1]},"o":{"x":[0.662,0.662,0.333],"y":[0,0,0]},"t":0,"s":[30,30,100]},{"i":{"x":[0.379,0.379,0.667],"y":[1,1,1]},"o":{"x":[0.239,0.239,0.333],"y":[0.379,0.379,0]},"t":10.499,"s":[110,110,100]},{"t":23,"s":[133,133,100]}],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":2,"nm":"组 7","refId":"5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":8.785,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":12.08,"s":[100]},{"t":20.866,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":0,"s":[245.648,257.655,0],"to":[0,11.333,0],"ti":[0,-11.333,0]},{"t":18,"s":[245.648,325.655,0]}],"ix":2},"a":{"a":0,"k":[10,25,0],"ix":1},"s":{"a":0,"k":[163,163,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":2,"nm":"图层 11","refId":"6","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":8.785,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":12.08,"s":[100]},{"t":20.866,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[228.533,184.47,0],"to":[0,12.333,0],"ti":[0,-12.333,0]},{"t":18,"s":[228.533,258.47,0]}],"ix":2},"a":{"a":0,"k":[1.5,20.5,0],"ix":1},"s":{"a":0,"k":[163,163,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":2,"nm":"图层 10","refId":"7","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":8.785,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":12.08,"s":[100]},{"t":20.866,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[313.447,257.655,0],"to":[-22.167,0,0],"ti":[22.167,0,0]},{"t":18,"s":[180.447,257.655,0]}],"ix":2},"a":{"a":0,"k":[71,2,0],"ix":1},"s":{"a":0,"k":[163,163,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":2,"nm":"爆开光.png","cl":"png","parent":12,"refId":"8","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[35.568]},"o":{"x":[0.333],"y":[0]},"t":2,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.154]},"t":11,"s":[100]},{"t":15,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-111.062,-2.5,0],"ix":2},"a":{"a":0,"k":[-4,67.5,0],"ix":1},"s":{"a":0,"k":[-212.5,212.5,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":2,"nm":"爆开光.png","cl":"png","parent":12,"refId":"8","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[35.568]},"o":{"x":[0.333],"y":[0]},"t":2,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0.154]},"t":11,"s":[100]},{"t":15,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[106.437,-2.5,0],"ix":2},"a":{"a":0,"k":[-4,67.5,0],"ix":1},"s":{"a":0,"k":[212.5,212.5,100],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":3,"nm":"Null 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[232,232,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.088,0.088,0.25],"y":[1,1,1]},"o":{"x":[0.226,0.226,0.33],"y":[0,0,0]},"t":0,"s":[40,40,100]},{"t":15,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":25,"st":0,"bm":0}],"markers":[],"tiny":0.4}
\ No newline at end of file
{
"code": "000000",
"data": {
"isOpenMember": 1,
"newerBelongPrize": "",
"memberGrade": 0,
"showNotice": false,
"end": false,
"detail": {
"feedTime": 1623242500923,
"showNewGiftPop": true,
"milkCreateTime": 1623242500923,
"feedWeight": 500,
"activityId": "60a60966114fbb7eb9b576ab",
"delTaskInfoTag": true,
"cowName": "小Q",
"guideStep": 4,
"userNick": "我",
"grassGrowTime": 1623242663382,
"gainCowMilkBottlesTime": 1623240837744,
"taskInfo": {
"foreverLimit": {
"focusShop": [],
"beMember": []
}
},
"tag": 0,
"reduceMilkDropsCount": 0,
"nextMilkCreateTime": 1623242950923,
"milkDrops": [],
"cowId": "60c0a3f667f1372ade1bb80b",
"guideisEnd": true,
"clickCrazyGainGrassTime": "",
"feedInfo": "",
"updateTime": 1623242663403,
"avatar": "http://wwc.alicdn.com/avatar/getAvatar.do?userIdStr=O8gbM07HMG9eOHRhPFxYMF*evCHbPHReMC-HP0cWMCcT&width=80&height=80&type=sns",
"cowMilkBottles": 2,
"cowLevel": 2,
"growthValue": 12,
"gainCowMilkBottlesTotal": 2,
"clickCrazyGainGrassCount": 0,
"progressGrassWeight": 107,
"milkWeight": 250,
"_id": "60c0a3f60cb7332a070d5c9c",
"createGrassWeight": 0
},
"shopUrl": "//market.m.taobao.com/apps/market/shopmember/index.html?wh_weex=true&sellerId=2207623078795&extraInfo=%7B%22source%22%3A%22isvapp%22%2C%22entrance%22%3A%22duiba%22%7D",
"contentArr": [
"玉立测试活动",
"玉立测试活动"
],
"newerBelongPrizeIsReceived": false,
"isVip": false
},
"success": true,
"message": "成功"
}
{
"code": "000000",
"data": {
"feedTime": 1623242500923,
"showNewGiftPop": true,
"milkCreateTime": 1623242500923,
"feedWeight": 500,
"activityId": "60a60966114fbb7eb9b576ab",
"delTaskInfoTag": true,
"cowName": "小Q",
"guideStep": 4,
"userNick": "我",
"grassGrowTime": 1623242693835,
"gainCowMilkBottlesTime": 1623240837744,
"end": false,
"taskInfo": {
"foreverLimit": {
"focusShop": [],
"beMember": []
}
},
"tag": 0,
"nextMilkCreateTime": 1623242890923,
"milkDrops": [],
"cowId": "60c0a3f667f1372ade1bb80b",
"guideisEnd": true,
"clickCrazyGainGrassTime": "",
"newerBelongPrize": "",
"feedInfo": "",
"updateTime": 1623242693847,
"avatar": "http://wwc.alicdn.com/avatar/getAvatar.do?userIdStr=O8gbM07HMG9eOHRhPFxYMF*evCHbPHReMC-HP0cWMCcT&width=80&height=80&type=sns",
"cowMilkBottles": 2,
"milkProduceGap": 450000,
"cowLevel": 2,
"growthValue": 12,
"gainCowMilkBottlesTotal": 2,
"clickCrazyGainGrassCount": 0,
"progressGrassWeight": 111,
"milkWeight": 250,
"_id": "60c0a3f60cb7332a070d5c9c",
"createGrassWeight": 0,
"newerBelongPrizeIsReceived": false
},
"success": true,
"message": "成功"
}
{
"code": "0000000000",
"data": {
"creditsConf": {
"creditsUp": 100,
"creditsType": "virtual",
"creditsDown": 50,
"prize": [
{
"img": "adsfsadf",
"credits": 20,
"id": 4,
"title": "0.3"
},
{
"img": "sadfasdf",
"credits": 150,
"id": 3,
"title": "1.5倍"
},
{
"img": "sadfasdf",
"credits": 100,
"id": 2,
"title": "1倍"
},
{
"img": "sadfasdf",
"credits": 50,
"id": 1,
"title": "0.5倍"
}
]
},
"floating": {
"jsTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191434.js",
"cssTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191440.css"
},
"options": [
{
"itemId": 47861,
"hidden": false,
"prizeType": "thanks",
"name": "谢谢参与",
"description": "",
"logo": "//yun1.duiba.com.cn/upload/uP99F1462438316972.png",
"id": 15581
},
{
"itemId": 47862,
"hidden": false,
"prizeType": "lucky",
"name": "幸运福袋",
"description": "",
"logo": "//yun1.duiba.com.cn/webapp/img/luckynewn.png",
"id": 15582
},
{
"itemId": 47863,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
},
{
"itemId": 47864,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
}
],
"rule": "adsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【iadsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【iadsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【i",
"type": "hdtool",
"element": {
"isCreditsTypeOpen": false,
"myCreditsLong": 999999632167,
"freeLimit": 5,
"success": false,
"myCredits": "999999632167",
"needCredits": "100",
"freeEmpty": true,
"needCreditsLong": 9,
"status": 7
},
"coinPusherConf": {
"exchangeRate": 60,
"creditsGear": "25,60,75,80"
}
},
"success": true,
"desc": "OK",
"timestamp": 1548832971636
}
\ No newline at end of file
{
"code": "0000000000",
"data": {
"creditsConf": {
"creditsUp": 100,
"creditsType": "virtual",
"creditsDown": 50,
"prize": [
{
"img": "adsfsadf",
"credits": 20,
"id": 4,
"title": "0.3"
},
{
"img": "sadfasdf",
"credits": 150,
"id": 3,
"title": "1.5倍"
},
{
"img": "sadfasdf",
"credits": 100,
"id": 2,
"title": "1倍"
},
{
"img": "sadfasdf",
"credits": 50,
"id": 1,
"title": "0.5倍"
}
]
},
"floating": {
"jsTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191434.js",
"cssTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191440.css"
},
"options": [
{
"itemId": 47861,
"hidden": false,
"prizeType": "thanks",
"name": "谢谢参与",
"description": "",
"logo": "//yun1.duiba.com.cn/upload/uP99F1462438316972.png",
"id": 15581
},
{
"itemId": 47862,
"hidden": false,
"prizeType": "lucky",
"name": "幸运福袋",
"description": "",
"logo": "//yun1.duiba.com.cn/webapp/img/luckynewn.png",
"id": 15582
},
{
"itemId": 47863,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
},
{
"itemId": 47864,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
}
],
"rule": "adsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【iadsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【iadsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【i",
"type": "hdtool",
"element": {
"isCreditsTypeOpen": false,
"myCreditsLong": 999999632167,
"freeLimit": 5,
"success": false,
"myCredits": "999999632167",
"needCredits": "100",
"freeEmpty": true,
"needCreditsLong": 9,
"status": 7
},
"coinPusherConf": {
"exchangeRate": 60,
"creditsGear": "25,60,75,80"
}
},
"success": true,
"desc": "OK",
"timestamp": 1548832971636
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548915321930,
"data":123456
}
\ No newline at end of file
{
"code": "000000",
"data": {
"showNewGiftPop": false,
"activityId": "5f855a0a738989848ebb5050",
"guideStep": 4,
"userNick": "卿卿我我",
"gainCowMilkBottlesTime": "",
"end": false,
"taskInfo": {
"freeReceive": 2,
"foreverLimit": {
"focusShop": [
{
"grass": 12222,
"isReceive": false,
"time": 1602727797457
}
],
"beMember": [
{
"grass": 12,
"isReceive": false,
"time": 1602727797427
}
]
},
"2020/10/15": {
"todayCompleteTaskTimes": 2
}
},
"tag": 0,
"nextMilkCreateTime": 1602904190337,
"milkDrops": [
{
"createTime": 1602679659133
},
{
"createTime": 1602679809133
},
{
"createTime": 1602679959133
},
{
"createTime": 1602680109133
},
{
"createTime": 1602680259133
},
{
"createTime": 1602680409133
},
{
"createTime": 1602680559133
},
{
"createTime": 1602680709133
},
{
"createTime": 1602680859133
},
{
"createTime": 1602681009133
},
{
"createTime": 1602681159133
},
{
"createTime": 1602681309133
},
{
"createTime": 1602681459133
},
{
"createTime": 1602681609133
},
{
"createTime": 1602681759133
},
{
"createTime": 1602681909133
},
{
"createTime": 1602682059133
},
{
"createTime": 1602682209133
},
{
"createTime": 1602682359133
},
{
"createTime": 1602682509133
}
],
"cowId": "5f86f0ede5c0d7316b457dd8",
"guideisEnd": true,
"clickCrazyGainGrassTime": "",
"newerBelongPrize": "",
"feedInfo": {},
"eachDropReduceTime": 5,
"updateTime": 1602903776711,
"milkProduceGap": 450000,
"gainCowMilkBottlesTotal": 0,
"clickCrazyGainGrassCount": 0,
"milkWeight": 250,
"_id": "5f86f0ed964f97d1ee73633a",
"speedUpEndTime": 1602683250085,
"newerBelongPrizeIsReceived": false
},
"success": true,
"message": "成功"
}
{
"code": "33000",
"data": {
"isOpenMember": false,
"newerBelongPrize": "",
"memberGrade": 1,
"showNotice": false,
"end": false,
"milkProduceGap": 450000,
"detail": {
"showNewGiftPop": false,
"activityId": "5f6fee6f114fbbc8c9935e9c",
"guideStep": 4,
"userNick": "卿卿我我",
"gainCowMilkBottlesTime": "",
"taskInfo": {
"freeReceive": 2,
"foreverLimit": {
"focusShop": [],
"beMember": []
},
"feedReceive": 2
},
"tag": 0,
"reduceMilkDropsCount": 0,
"nextMilkCreateTime": 1601272292257,
"milkDrops": [],
"cowId": "5f715eae0cb733e89283e0a2",
"guideisEnd": true,
"clickCrazyGainGrassTime": "",
"feedInfo": {},
"updateTime": 1601276726110,
"gainCowMilkBottlesTotal": 0,
"clickCrazyGainGrassCount": 0,
"milkWeight": 250,
"_id": "5f715eae52bbded304b20111"
},
"shopUrl": "//market.m.taobao.com/apps/market/shopmember/index.html?wh_weex=true&sellerId=2207623078795&extraInfo=%7B%22source%22%3A%22isvapp%22%2C%22entrance%22%3A%22duiba%22%7D",
"contentArr": [
"中秋节快乐1",
"中秋节快乐2",
"中秋节快乐3"
],
"newerBelongPrizeIsReceived": false,
"isVip": true
},
"success": true,
"message": "成功"
}
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1550570639368,
"data":{
"orderId":"883006813674240289",
"submitToken":"d895deb9118f4b938d0b70a3dd2ace19",
"credits":"999999491765",
"unitName":"金币",
"consumerCredits":999999491765
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548923950498,
"data":{
"element":{
"success":false,
"isCreditsTypeOpen":false,
"needCredits":"100",
"myCredits":"1123",
"myCreditsLong":1123,
"needCreditsLong":9,
"freeLimit":2,
"status":6,
"freeEmpty":true
},
"lottery":{
"id":null,
"type":"111",
"imgUrl":"//yun.duiba.com.cn/images/201607/73htz55ih9.jpg",
"link":null,
"title":"重复券测试grape",
"itemId":null,
"appItemId":null,
"bonus":null,
"bonusMin":null,
"bonusMax":null,
"needAccount":null,
"appLucky":null,
"tip":null,
"useBtnText":null,
"validate":null,
"couponCode":null,
"couponKey":null,
"stInfoDpmImg":null,
"stInfoDpmClose":null,
"stInfoDpmGoUse":null,
"showUse":null,
"openUrl":null,
"iosDownloadUrl":null,
"androidDownloadUrl":null,
"isDownloadUrl":null,
"confirm":null,
"phaseNumber":null,
"happyCode":null,
"appHidden":true,
"zybangJson":null
},
"exposure":11111,
"creditsInfo":{
"activityId":82567,
"prizeId":4,
"orderNum":null,
"developerBizId":"3029576",
"score":null,
"recordStatus":1,
"errorMsg":null
},
"againTag":null
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1550646190489,
"data":{
"score":100,
"maxScore":100
}
}
\ No newline at end of file
{
"data": {
"isContinue": true
},
"success": true,
"code": "veniam",
"message": "amet"
}
{"code":"430009","success":false,"message":"只有新会员才能助力哦~"}
{
"success": true,
"message": "ok",
"code": "111111",
"data": {
"_id": "1111",
"openId": "mfk",
"rule": "mfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfkmfk",
"startTime": 1599131034611,
"endTime": 1598585357782,
"activityStatus": 2,
"openPrizeStatus": 2,
"totalScore": 52000001,
"showImage": "https://yun.duiba.com.cn/aurora/assets/70c7fdc45ed8139bdc0a23ac004facc07abf3cfd.jpg"
}
}
{
"data": {
"score": 123456,
"gameTimes": 1,
"isFirstEnterGame": false
},
"success": true,
"code": "1",
"message": "ok"
}
{
"code": "111",
"success": true,
"message": "ok",
"data": {
"showAwardDialog": true,
"prize": {
"id": "id",
"useUrl": "useUrl",
"drawStatus": 1,
"type": 5,
"image": "https://yun.duiba.com.cn/aurora/assets/39c89bfa28c4c022436c23f56547b2995cb2b65c.png",
"name": "name"
},
"rank": {
"score": 0,
"rank": 200
}
}
}
{
"code": "111",
"success": true,
"message": "ok",
"data": {
"list": [
{
"useUrl": "useUrl",
"id": "id1",
"prizeId": "prizeId1",
"type": 4,
"image": "https://yun.duiba.com.cn/aurora/assets/39c89bfa28c4c022436c23f56547b2995cb2b65c.png",
"name": "name1",
"drawStatus": 1,
"addressDetail": "addressDetail",
"rank": "1-2"
},
{
"useUrl": "useUrl",
"id": "id2",
"prizeId": "prizeId2",
"type": 4,
"image": "https://yun.duiba.com.cn/aurora/assets/39c89bfa28c4c022436c23f56547b2995cb2b65c.png",
"name": "name2",
"drawStatus": 1,
"addressDetail": "addressDetail",
"rank": "3-5"
},
{
"useUrl": "useUrl",
"id": "id3",
"prizeId": "prizeId3",
"type": 4,
"image": "https://yun.duiba.com.cn/aurora/assets/39c89bfa28c4c022436c23f56547b2995cb2b65c.png",
"name": "name3",
"drawStatus": 1,
"addressDetail": "addressDetail",
"rank": "6-10"
}
]
}
}
{
"data": {
"rank": 11,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"userNick": "userNick",
"list": [
{
"rank": 1,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"score": 123456,
"userNick": "userNick1"
},
{
"rank": 2,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"score": 12345,
"userNick": "userNick2"
},
{
"rank": 3,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"score": 1234,
"userNick": "userNick3"
},
{
"rank": 4,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"score": 123,
"userNick": "userNick4"
},
{
"rank": 5,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"score": 12,
"userNick": "userNick5"
},
{
"rank": 6,
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"score": 1,
"userNick": "userNick6"
}
],
"score": "66666"
},
"success": true,
"code": "111",
"message": "ok"
}
{
"success": true,
"data": {
"isVip": true,
"url": "https://www.baidu.com/"
}
}
{
"data": {
"gameId": 12345,
"beMember": false,
"isFirstEnterGame": false
},
"success": true,
"code": "123",
"message": "ok"
}
{
"data": {
"prizeInfo": {
"id": "id",
"image": "https://img.alicdn.com/imgextra/i1/2275046294/O1CN01xTeKMI1wMhRux48Y6_!!2275046294-2-miniprogram.png",
"name": "name",
"type": 4
},
"score": 6666,
"rank": 12,
"userNick": "hycv",
"avatar": "esse veniam ut",
"gameTimes": 0,
"maxScore": 1234,
"getScore": 66
},
"success": true,
"code": "1",
"message": "ok"
}
{
"success": true,
"data": {
"avatar": "https://source.unsplash.com/user/erondu/76x76",
"nickName": "我啊是大请问",
"activityId": "string",
"inviteId": "",
"isFollow": true,
"openId": "string",
"firstLoginToday": true,
"newUser": false
}
}
{
"success": false,
"code": "ipsum voluptate est pariatur aliqua",
"message": "commodo ipsum tempor",
"data": "123"
}
\ No newline at end of file
{
"success": false,
"code": "ipsum voluptate est pariatur aliqua",
"message": "commodo ipsum tempor",
"data": "123"
}
\ No newline at end of file
{
"success": true,
"code": "ipsum voluptate est pariatur aliqua",
"message": "commodo ipsum tempor",
"data": "123"
}
\ No newline at end of file
{
"code": null,
"data": {
"creditsUnit": "人民币123123",
"difficulty": 1,
"freeTimes": 0,
"levelInfo": [
{
"name": "D",
"score": 50
},
{
"name": "C",
"score": 100
},
{
"name": "B",
"score": 150
},
{
"name": "A",
"score": 200
},
{
"name": "A+",
"score": 300
},
{
"name": "S",
"score": 500
},
{
"name": "SSS",
"score": 1000
}
],
"music": false,
"spNum": [
{
"num": 200,
"spName": "游戏积分",
"ticketType": "start"
},
{
"num": 150,
"spName": "复活积分",
"ticketType": "resurgence"
},
{
"num": 1,
"spName": "直冲云霄积分",
"ticketType": "fly"
},
{
"num": 8,
"spName": "双倍金币续费积分",
"ticketType": "gold_double_renew"
},
{
"num": 33,
"spName": "三倍金币积分",
"ticketType": "gold_triple"
},
{
"num": 21,
"spName": "金身续费积分",
"ticketType": "invincible_renew"
}
]
},
"message": null,
"success": true
}
\ No newline at end of file
{
"success": true,
"code": "ipsum voluptate est pariatur aliqua",
"message": "commodo ipsum tempor",
"data": {
"startId": "77777",
"scorePreRound": -59955755.34276232
}
}
\ No newline at end of file
{
"success": true,
"code": "ipsum voluptate est pariatur aliqua",
"message": "commodo ipsum tempor",
"data": {
"startId": "77777",
"scorePreRound": 1234,
"firstDouble": false,
"firstInvincible": false
}
}
\ No newline at end of file
{
"success": true,
"code": "sed tempor proident Excepteur in",
"message": "magna incididunt",
"data": {
"prizeId": "sp",
"url": "aliquip veniam",
"name": "xxxxx",
"icon": "//yun.duiba.com.cn/spark/assets/9ff9e1f358db0ea9027edaca04247e62fd52b22d.png"
}
}
\ No newline at end of file
{
"success": true,
"code": "labore qui nulla dolor mollit",
"message": "deserunt"
}
\ No newline at end of file
{
"success": true,
"message": "ut ipsum",
"data": "1"
}
\ No newline at end of file
{
"data": 1,
"success": "true",
"message": "Lorem dolore ea aliquip Duis"
}
\ No newline at end of file
{
"code": "000000",
"data": {
"prizeList": [
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i1/676606897/O1CN01LSRArg20osHsZ0WIr_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 1,
"probability": "",
"openId": "AAGMBAINAMTJSjCbJXOUEPSv",
"updateTime": 1599704766652,
"goodId": "616444374083",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599457433502,
"deleteStatus": 1,
"name": "1111",
"rank": "1-5",
"_id": "5f55c899964f9706aac97635",
"stock": "",
"desc": "12"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i4/676606897/O1CN011wSmP820osHsfbQVt_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 2,
"probability": "",
"updateTime": 1599704766657,
"goodId": "619250976552",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599630352681,
"deleteStatus": 1,
"name": "2222",
"rank": "6-10",
"_id": "5f586c10738989c8b3699c36",
"stock": "",
"desc": "请问"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i2/676606897/O1CN01jSu8pl20osHpoItcH_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 3,
"probability": "",
"updateTime": 1599704766662,
"goodId": "619551785682",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599630352691,
"deleteStatus": 1,
"name": "333",
"rank": "11-15",
"_id": "5f586c10ef5071ef85b121d8",
"stock": "",
"desc": "问问"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i4/676606897/O1CN01052oCs20osHpgeJo1_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 4,
"probability": "",
"updateTime": 1599704766667,
"goodId": "619551785682",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599630352702,
"deleteStatus": 1,
"name": "444",
"rank": "16-25",
"_id": "5f586c10114fbb8f6d936a84",
"stock": "",
"desc": "抬头"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i1/676606897/O1CN01Eomi5d20osHqufhQS_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 5,
"probability": "",
"updateTime": 1599704766671,
"goodId": "619250976552",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599631028489,
"deleteStatus": 1,
"name": "5555",
"rank": "26-190",
"_id": "5f586eb40cb7330c942fa945",
"stock": "",
"desc": "55555"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i3/676606897/O1CN01c5dDdr20osHnlbxH8_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 6,
"probability": "",
"updateTime": 1599704766678,
"goodId": "",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599704598695,
"deleteStatus": 1,
"name": "123",
"rank": "191-192",
"_id": "5f598e16e5c0d7361f94443c",
"stock": "",
"desc": "12"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i4/676606897/O1CN018xPsWm20osHsVvmQ4_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 7,
"probability": "",
"updateTime": 1599704766682,
"goodId": "",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599704598700,
"deleteStatus": 1,
"name": "123",
"rank": "193-194",
"_id": "5f598e1685a7496423364b2c",
"stock": "",
"desc": "123"
},
{
"switchStock": 2,
"image": "https://img.alicdn.com/imgextra/i2/676606897/O1CN01ZfJo7d20osHtzfobK_!!676606897-0-miniprogram.jpg",
"useUrl": "",
"level": 8,
"probability": "",
"updateTime": 1599704766687,
"goodId": "",
"type": 3,
"prizeDataType": 1,
"activityId": "5f55c899964f9706aac97634",
"ename": "",
"credits": "",
"createTime": 1599704598706,
"deleteStatus": 1,
"name": "123",
"rank": "195-196",
"_id": "5f598e1667f1376654eb7d4d",
"stock": "",
"desc": "314"
}
],
"detail": {
"userNick": "金刚猫燕",
"rank": 15,
"totalScore": 190
},
"list": [
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "啊大苏打",
"totalScore": 123123
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "qweqwe",
"totalScore": 123123
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "啊实打实的",
"totalScore": 123123
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "趣味请问",
"totalScore": 123123
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "q123123",
"totalScore": 123123
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "啊大苏打",
"totalScore": 3444
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "啊大苏打",
"totalScore": 54345
},
{
"_id": "ea cupidatat occaecat dolor",
"avatar": "deserunt occaecat proident ex Lorem",
"openId": "pariatur",
"userNick": "啊大苏打",
"totalScore": 5663454
}
]
},
"success": true,
"message": "成功"
}
{
"success": true,
"message": "",
"code": "",
"data": {
"ruleIdList": [
"ru_1",
"ru_2",
"ru_3",
"ru_4"
],
"drawStatus": 12,
"prizeId": "aa",
"gameCounts": 1
}
}
\ No newline at end of file
{
"success": true,
"message": "",
"code": "",
"data": 1234
}
\ No newline at end of file
{
"success": true,
"message": "",
"code": "",
"data": {
"type": 1,
"status": 1,
"prize": {
"prizeId": "sp_1",
"prizeType": 1,
"optionId": "sdhjfhjhjjj",
"optionName": "10元话费",
"optionImg": "https://www.baidu.com/xxoo2.png",
"userRecordId": 1235,
"url": "https://www.baidu.com/order/1235"
}
}
}
\ No newline at end of file
{
"success": true,
"message": "",
"data": "<p class=\"p1\">1、什么人可以参与抽奖?</p><p class=\"p1\">同时持有中信银行借记卡和信用卡的客户,活动期间内预约报名(每个自然月均可报名),完成绑定中信银行借记卡并用中信银行手机银行app对本人绑定的信用卡进行自动还款任务即视为达标获得抽奖资格。达标用户将以短信形式通知抽奖。 </p><p>  </p><p class=\"p1\">2、抽奖的时间是什么时候?</p><p class=\"p1\">报名成功次月10日-15日。每期的抽奖资格当期有效,若满足抽奖资格未在有效期内抽奖,资格不保留。首轮达标客户的抽奖开启时间为:7月10-15日。</p><p>  </p><p class=\"p1\">3、活动说明:</p><p class=\"p1\">1)点击“立即抽奖”按钮,摇奖机开始转动,最终摇奖机中间停留的即为您所中的奖品。</p><p class=\"p1\">2)活动期间,每位客户每个自然月均可报名参与活动,预约报名并完成绑定中信银行借记卡并用中信银行手机银行app对本人绑定的信用卡进行自动还款任务即视为达标获得抽奖资格,可获抽奖资格,每位客户每个自然月最多可获一次抽奖机会,请在抽奖有效期内(报名次月10日—15日)通过短信路径或登录手机银行首页——特色服务——还款抽奖——进入页面抽奖,每期的抽奖资格当期有效,若满足抽奖资格未在有效期内抽奖,资格不保留。</p><p class=\"p1\">3)客户抽中的“10元话费”奖励将在当月30日前直接充值到您预留报名的手机号码中,请注意查收;</p><p class=\"p1\">4)大牌券奖励中奖后客户可在活动页面右上角的【我的奖品】中找到,奖品具体使用规则可在奖品详情页查看,大牌权益奖励兑换及使用将会跳转至权益对应的提供方平台,您填写的信息仅用于奖品或权益发放时使用(如姓名、手机号、地址等)。本活动服务由第三方杭州兑吧网络科技有限公司提供,相关责任将由杭州兑吧网络科技有限公司承担,如有问题请咨询该公司客服。中信银行仅为相关活动提供链接服务,不提供任何形式的担保和承诺。大牌券的领取使用有任何问题请致电兑吧客服专线:400-609-0828;</p><p class=\"p1\">5)为保证活动的公平公正,通过不当手段、利用系统漏洞恶意套取奖励等不当途径参与本活动抽奖的客户,中信银行有权终止该客户参与活动的权利并取消其获奖资格;</p><p class=\"p1\">6)凡参与活动的客户,即视为接受活动所有规则,在法律允许范围内,中信银行保留对本次活动的解释权、随时调整本活动优惠信息、变更活动的权利;</p><p class=\"p1\">7)通过本软件参加的任何商业活动,均与Apple Inc.无关;</p><p><span style=\"font-size:10.5ptpx\">8)本次活动授权杭州兑吧网络科技有限公司提供营销服务,若有相关疑问,请致电兑吧客服专线:400-609-0828。</span></p>"
}
\ No newline at end of file
{}
\ No newline at end of file
import { GDispatcher } from "../src";
interface ResData {
/**
* 分组数据
*/
groups: GroupInt[];
//暂时没有工具,不用
resources?: any;
path?: string;
}
interface GroupInt {
/**
* 所有的资源名字,根据,分割,根据后缀区分类型
*
*/
keys: string;//"aa.png,bb.jpg,name.json"
/**
* 文件夹名字吧
*/
name: string;
/**
* 图集
* 线上打包合图可能有多张,暂时发现texturePacker版本问题只有一张
*/
atlas: {
[name: string]: {
"x": number,
"y": number,
"w": number,
"h": number,
"ox": number,
"oy": number,
"sw": number,
"sh": number,
"ro": boolean
},
};
}
interface SkinInt {
name: string,
x: 0,
y: 0,
type: 'container' | 'text' | 'button' | 'sprite' | 'rect' | 'item',//item的不初始化进节点,只作为数据
children?: SkinInt[],
id?: string,
alpha: number,
props?: {
source?: string,
text: string,
size: number,
fillColor: string,
textAlpha: number,
width: number,
height: number,
tUp: string,
tDown: string,
tDisable: string
}
}
/**
* 简单点,有工具的话像egret那样玩,可以自动生成图片组数据
*/
export namespace RES {
let resData: ResData
/**
* 资源路径
*/
export let resPath: string;
/**
* RES单独缓存一下纹理,全局的FYGE缓存纹理对于多page有覆盖的问题;
*/
let textureHash: {
[name: string]: FYGE.Texture;
} = {};
/**
* movieClip的ve数据
*/
let videoEntityHash: {
[name: string]: SvgaParser.VideoEntity
} = {};
/**
* 音频的加载
*/
let soundHash = {}
/**
* 记录组加载完成
*/
let groupsCompleteHash: {
[name: string]: boolean
} = {}
/**
* 记录加载的promise
*/
let groupsPromiseHash: {
[name: string]: Promise<any>
} = {}
/**
* 单独资源加载的promise记录
*/
let singleResPromiseHash: {
[name: string]: Promise<any>
} = {}
/**
*
* @param res 资源数据,就是对象,不考虑加载json先
* res格式{
* path:1111/
* groups: [
* {
*
* }
* ];
* }
*/
export function loadConfig(res) {
resData = res;
resPath = res.path;
}
/**
* 根据组名加载一组资源,通常用于加载一个视图的的所有资源
* 里的promise的resolve并没有返回值
* @param name
*/
export function loadGroup(name: string): Promise<void> {
//已经加载完成的直接返回
if (groupsCompleteHash[name]) {//其实直接return就行
return new Promise((resolve) => {
resolve()
})
}
//如果是正在加载中的,返回正在加载中的promise
if (groupsPromiseHash[name]) {
return groupsPromiseHash[name];
}
//如果首次加载
//获取资源组
let arr = getGroupResByName(name);
//如果不存在arr,直接返回空p,且标记完成
if (!arr || !arr.length) {
groupsCompleteHash[name] = true;
return new Promise((resolve) => {
resolve()
})
}
// 建一个promise
let p: Promise<void> = new Promise((resolve, reject) => {
loadResList((s) => {
//移除
delete groupsPromiseHash[name];
if (s) {
groupsCompleteHash[name] = true;
resolve()
} else {
reject();
}
}, arr/*, resPath + name*/)
})
groupsPromiseHash[name] = p;
return p;
}
/**
* var textue = await RES.getResAsync(str);
* @param str 可以是网络图片路径或键值
* @param comFun 加载回调
* @param thisObj this指向
*/
export function getResAsync(str: string, comFun?: (res: any, str: string) => void, thisObj?: any): Promise<any> {
// var arr = str.split(".");
var type = str.substring(str.lastIndexOf(".") + 1, str.length);
//如果是图片
if (type == "png" || type == "jpg") {
//原先就有了,加载过的,且已加载完成的
let cached = textureHash[str] || FYGE.TextureCache[str];
if (cached) {
//回调形式
comFun && comFun.call(thisObj, cached, str)
// return cached;
return new Promise((r) => { //为了能.then
r(cached)
})
}
//未加载完成的
else if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj)
}
else {
//判断是否在资源里,判断是否要加载图集,注意已排除jpg
var groupName = hasRes(str);
if (groupName && type != "jpg") {
var group = getGroupByName(groupName);
if (group && group.atlas) {
//加载图集,现在就一张,以后有机会改
var json = groupName + ".json"//group.atlas.split(",")[0];
//找json是否在加载中
if (singleResPromiseHash[json]) {
return singleResPromiseHash[json].then(
(r) => {
//正在加载中,getResAsync首次加载的回调会缓存,完成后返回需要的,
let cached = textureHash[str] || FYGE.TextureCache[str]
comFun && comFun.call(thisObj, cached, str)
return cached;
},
() => {
comFun && comFun.call(thisObj, null, str)
return null
}
)
} else {
return getResAsync(json)
.then(() => {
let cached = textureHash[str] || FYGE.TextureCache[str]
comFun && comFun.call(thisObj, cached, str)
return cached
}, () => {
comFun && comFun.call(thisObj, null, str)
return null
})
}
}
}
var src = groupName ? resPath + groupName + "/" + str : str;
var p = new Promise((resolve, reject) => {
FYGE.GlobalLoader.loadImage((s, image) => {
//移除
delete singleResPromiseHash[str];
//入缓存
if (s) {
let cached = FYGE.Texture.from(image);
//入RES,
textureHash[str] = cached;
//入全局
FYGE.Texture.addToCache(cached, str);
comFun && comFun.call(thisObj, cached, str)
resolve(cached)
} else {
comFun && comFun.call(thisObj, null, str)
reject()
}
}, src)
})
singleResPromiseHash[str] = p
return p
}
}
else if (type == "svga") {
if (videoEntityHash[str]) {
comFun && comFun.call(thisObj, videoEntityHash[str], str)
return new Promise((r) => {
r(videoEntityHash[str])
})
}
//未加载完成的
else if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj)
} else {
var groupName = hasRes(str);
var src = groupName ? resPath + groupName + "/" + str : str;
var p = new Promise((resolve, reject) => {
SvgaParser.loadSvga(
src,
(v) => {
delete singleResPromiseHash[str];
videoEntityHash[str] = v;
comFun && comFun.call(thisObj, v, str)
resolve(v)
},
(err) => {
delete singleResPromiseHash[str];
comFun && comFun.call(thisObj, null, str)
reject(err)
}
)
})
singleResPromiseHash[str] = p;
return p
}
}
//json图集的话,不晓得用啥判断加载完成,所以不删除promise吧,其实json可能只是数据,不管先
else if (type == "json") {
if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj)
} else {
var groupName = hasRes(str);//json现在肯定在内,暂时不能加载其他域名的json
var src = groupName ? resPath + groupName + "/" + str : str;
var p = new Promise((resolve, reject) => {
var jsonData = getGroupByName(groupName).atlas
FYGE.GlobalLoader.loadImage((s, data) => {
if (s) {
//createTextureSheet会自行缓存全局
var t = FYGE.createTextureSheet(new FYGE.BaseTexture(data/*.img*/), jsonData)
//缓存进RES
for (let key in t) textureHash[key] = t[key];
comFun && comFun.call(thisObj, t, str)
resolve(t)
} else {
//加载失败,移除要,否则再次触发加载会出问题
delete singleResPromiseHash[str];
comFun && comFun.call(thisObj, null, str)
reject()
}
}, src.replace("json", "png"))
})
singleResPromiseHash[str] = p
return p
}
}
}
/**
* 待写,根据网络路径加载图片
*/
export function getResByUrl() {
}
/**
* 获取素材,
* @param str
* @return 已加载好得素材或null
*/
export function getRes(str: string)/*: Texture | VideoEntity*/ {
if (!str) return null;
var type = str.substring(str.lastIndexOf(".") + 1, str.length);
if (type == "png" || type == "jpg") {
return textureHash[str] || FYGE.TextureCache[str] || null;
}
else if (type == "svga") {
return videoEntityHash[str] || null;
}
else if (type == "mp3") {
return soundHash[str] || null;
}
}
/**
* 偷懒的方法,加载配置里所有的资源,基本也不用
*/
export function loadAllGroup() {
var groups = resData.groups;
var p = []
groups.forEach((g) => {
p.push(loadGroup(g.name))
})
return Promise.all(p)
}
/***乱改 */
export function loadAllGroupForProgress() {
return new Promise(r => {
var groups = resData.groups;
let index = 0
groups.forEach(async (g) => {
await loadGroup(g.name)
index++
GDispatcher.dispatchEvent("loadPer", index / (groups.length - 1))
if (index == groups.length - 1) {
r(0)
}
})
})
}
/**
* 判断是否在资源组里
* 考虑是否init就做表
* 有就返回组名,为了加载路径,不然以后有工具可以放入resources
*/
function hasRes(str: string): string {
for (var i = 0; i < resData.groups.length; i++) {
var group = resData.groups[i];
var keys = group.keys;
if (keys && keys.split(",").indexOf(str) > -1) {
return group.name;
}
//如果是图集的json,altas现在是图集
if (group.atlas && group.name + ".json" == str) {
return group.name;
}
}
return null
}
/**
* 处理数据,获得所有资源单项
* @param name
*/
function getGroupResByName(name: string) {
var group: GroupInt = getGroupByName(name);
if (!group) return null;
//判断加载图集还是单图
if (group.atlas) {
// var arr: string[] = [].concat(group.atlas.split(","));
var arr = [name + ".json"]
//再添加非图片的资源,和图集已排除jpg
if (group.keys) {
arr = arr.concat(group.keys.split(",").filter((k: string) => {
return k.substr(-4) != ".png" //&& k.substr(-4) != ".jpg"
}))
}
return arr
}
else if (group.keys) {
return group.keys.split(",")
} else {
return null
}
}
/**
* 根据名字找组
* @param name
*/
function getGroupByName(name: string): GroupInt {
var groups = resData.groups;
var group: GroupInt;
for (var i = 0; i < groups.length; i++) {
if (groups[i].name === name) {
group = groups[i];
break;
}
}
return group
}
/**
* 新版的加载一列资源
* @param callback
* @param arr
*/
function loadResList(callback: (allLoaded: boolean) => void, arr: string[]) {
let count = 0;
let countAll = arr.length;
if (!countAll) callback(true);
let mark = true;
for (var i = 0; i < countAll; i++) {
let resName = arr[i];
getResAsync(resName, (res, str) => {
//标记失败,如果有一项资源加载失败,标记下
if (!res) mark = false
if (++count == countAll) callback(mark);
}, this)
}
}
/**
*
* @param str
* @param comFun
* @param thisObj
*/
function returnSingleResPromise(str: string, comFun?: (res: any, str: string) => void, thisObj?: any) {
//已判断是否存在
singleResPromiseHash[str].then(
(r) => {
comFun && comFun.call(thisObj, r, str)
},
() => {
comFun && comFun.call(thisObj, null, str)
}
)
return singleResPromiseHash[str];
}
//皮肤相关的也放在RES吧
let skinData: SkinInt
/**
* 添加皮肤配置文件
*/
export function loadSkinConfig(skinJson) {
skinData = skinJson;
}
/**
* 根据
* @param con 添加显示对象的容器
* @param skin 皮肤名字或数据
* @param root 根容器,为了添加自定义引用
*/
export function initSkinDisplay(con: FYGE.Container, skin: string | SkinInt, root?: FYGE.Container) {
//@ts-ignore
var data: SkinInt = typeof (skin) == 'string' ? getSkinDataByName(skin) : skin;
if (!data.children || !data.children.length) return;
// for (var i = data.children.length - 1; i >= 0; i--) {
for (var i = 0; i < data.children.length; i++) {
var child = data.children[i];
if (child.type == "item") continue;
var dis = con.addChild(getDisplayByData(child));
if (root && child.id) root[child.id] = dis;
if (child.type == "container") initSkinDisplay(dis, child, root);
}
}
/**
* 遍历根据名字找节点数据,只会是container的
* @param skinName
*/
export function getSkinDataByName(skinName: string, skinNode: SkinInt = skinData): SkinInt {
if (!skinNode || !skinNode.children || !skinNode.children.length) return null;
for (var i = 0; i < skinNode.children.length; i++) {
var child = skinNode.children[i];
if (child.name == skinName && (child.type == "container" || child.type == "item")) return child;
var gson = getSkinDataByName(skinName, child);
if (gson) return gson
}
return null;
}
/**
* 通过数据创建显示对象
* @param data
*/
function getDisplayByData(data: SkinInt): FYGE.Container {
var dis: FYGE.Container;
switch (data.type) {
case "container":
dis = new FYGE.Container();
break;
case "button":
dis = new FYGE.Button(
getRes(data.props.tUp),
data.props.tDown ? getRes(data.props.tDown) : null,
data.props.tDisable ? getRes(data.props.tDisable) : null,
);
break;
case "text":
dis = new FYGE.TextField();
for (let key in data.props) dis[key] = data.props[key];
break;
case "sprite":
dis = new FYGE.Sprite(getRes(data.props.source));
break;
case "rect":
// dis = new FYGE.Graphics()
// .beginFill(data.props.fillColor)
// .drawRect(0, 0, data.props.width, data.props.height)
// .endFill();
dis = new FYGE.Shape()
//@ts-ignore
dis.beginFill(FYGE.string2hex(data.props.fillColor))
//@ts-ignore
dis.drawRect(0, 0, data.props.width, data.props.height)
//@ts-ignore
dis.endFill();
break;
}
dis.name = data.name;
dis.alpha = data.alpha || 1;
dis.position.set(data.x, data.y);
// if (data.type == "text") dis.y -= 4;//文本莫名偏下,移动下,手机调试的时候也试试
return dis;
}
/**
* 销毁组纹理
* 线上才有用,待测试,TODO
* @param name
*/
export function destroyGroup(name: string) {
var group: GroupInt = getGroupByName(name);
if (!group) return;
var arr = [];
if (group.keys) {
arr = group.keys.split(",")
}
var removedBase = [];
//散图清除
for (var i = 0; i < arr.length; i++) {
var t: FYGE.Texture = getRes(arr[i]);
if (t) {
//base的清除,不要重复清除
if (removedBase.indexOf(t.baseTexture) == -1) {
t.baseTexture.destroy();
removedBase.push(t.baseTexture)
}
//自己纹理清除
t.destroy();
}
//RES里单独缓存的清除
delete textureHash[arr[i]]
}
}
//貌似不需要,为了加载过一次的资源不用重新加载
function destroyRES() {
}
}
/**
* 到时放到Loader里,增加open类型、headers、参数、等等
* @param options
*/
export function ajax(options: ajaxParameterInt) {
/**
* 默认为GET请求
*/
options.type = options.type || "GET";
/**
* 返回值类型默认为json
*/
options.dataType = options.dataType || 'json';
/**
* 默认为异步请求
*/
options.async = options.async === false ? false : true;
/**
* 对需要传入的参数的处理
*/
var params = getParams(options.data);
var xhr: XMLHttpRequest;
/**
* 创建一个 ajax请求
* W3C标准和IE标准
*/
if (window["XMLHttpRequest"]) {
//W3C标准
xhr = new window["XMLHttpRequest"]();
} else if (window["ActiveXObject"]) {
//@ts-ignore IE标准
xhr = new ActiveXObject('Microsoft.XMLHTTP')
} else {
console.error("当前浏览器不支持XHR请求")
return
}
//返回类型
xhr.responseType = options.dataType;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var status = xhr.status;
if (status >= 200 && status < 300) {
options.success && options.success(xhr.response);
} else {
options.error && options.error(status || "error");
}
}
};
if (options.type == 'GET') {
xhr.open("GET", options.url + '?' + params, options.async);
xhr.send(null)
} else if (options.type == 'POST') {
/**
*打开请求
*/
xhr.open('POST', options.url, options.async);//待测试,post请求
/**
* POST请求设置请求头
*/
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
if (options.headers) {
for (let key in options.headers) {
xhr.setRequestHeader(key, options.headers[key]);
}
}
/**
* 发送请求参数
*/
xhr.send(params);
}
}
/**
* jsonp模拟,不考虑回调
* @param url
* @param params
*/
export function jsonp(url: string, params: any) {
const src = url + '?' + getParams(params);
const scriptEl = document.createElement('script');
scriptEl.src = src;
scriptEl.onload = function () {//docment考虑改成head
document.body.removeChild(scriptEl);
};
scriptEl.onerror = function () {
document.body.removeChild(scriptEl);
};
document.body.appendChild(scriptEl);
}
/**
* 对象参数的处理
* @param data
* @returns {string}
*/
function getParams(data): string {
if (!data) return "";//没有就返回空字符
var arr = [];
for (var param in data) {
arr.push(encodeURIComponent(param) + '=' + encodeURIComponent(data[param]));
}
//不缓存
arr.push('_=' + Date.now());
return arr.join('&');
}
//基本没用到过cache,先不加
interface ajaxParameterInt {
url: string,
data?: any,
type?: "GET" | "POST",
async?: boolean,
dataType?: 'text' | 'json' | 'arraybuffer',
headers?: any,
success?: (res: any) => void,
error?: (err: any) => void
}
/**
* 对封装好的ajax请求进行调用
* */
// ajax({
// url: "", //请求地址
// type: 'GET', //请求方式
// data: { name: 'zhangsan', age: '23', email: '2372734044@qq.com' }, //请求参数
// dataType: "json", // 返回值类型的设定
// async: false, //是否异步
// headers: {},
// success: function (response) {
// console.log(response); // 此处执行请求成功后的代码
// },
// error: function (status) {
// console.log('状态码为' + status); // 此处为执行成功后的代码
// }
// });
import { destroyWaiting } from "./waitingCtrl";
import PanelCtrl from "./panelCtrl";
import SceneCtrl from "./sceneCtrl";
import { destroyToast } from "./toastCtrl";
import ConfirmPanel from "../../src/common/IConfirmPanel";
export { showToast } from "./toastCtrl";
export * from "./waitingCtrl";
/**
* 展示弹框
* @param panel 弹框类
* @param data 数据
*/
export const showPanel = (panel: any, data?: any) => {
return PanelCtrl.instance.show(panel, data)
}
export const showConfirm = (panel: any, data?: any) => {
const confirmPanel: ConfirmPanel = PanelCtrl.instance.show(panel, data);
return confirmPanel.makePromise();
}
/**
* 关闭所有弹框
*/
export const closeAllPanels = () => {
PanelCtrl.instance.closeAll();
}
/**
* 关闭当前弹框
*/
export const closeCurrentPanel = () => {
PanelCtrl.instance.closeCurrent();
}
/**
* 替换场景
* @param scene
* @param data
*/
export const changeScene = (scene: any, data?: any) => {
SceneCtrl.instance.change(scene, data)
}
/**
* 获取当前场景
*/
export function getCurrentScene(): any {
return SceneCtrl.instance.currentScene
}
/**
* 获取当前弹框
*/
export function getCurrentPanel(): any {
return PanelCtrl.instance.currentPanel
}
/**
* 淘宝小程序的alert
* @param {string} title
* @param {string} content
*/
export const showAlert = (title?: string, content?: string) => {
//@ts-ignore
if (my) {
//@ts-ignore
my.alert({
title: title || "",
content: content || ""
});
} else {
console.log(title, content)
}
}
/**
* 替换setTimeout 因为页面销毁时setTimeout不会停
* 所以干脆用Tween的
* @param {Function} callback
* @param {number} time 毫秒计
*/
export function wait(callback: () => void, time: number): {} {
let obj = {};
FYGE.Tween.get(obj)
.wait(time)
.call(callback)
return obj
}
export function clearWait(obj: {}) {
obj && FYGE.Tween.removeTweens(obj);
}
/**
* 递归清除显示对象里面所有的Tween
* @param obj
* @param isRecursive 默认true,递归移除子级
*/
export function removeTweens(obj, isRecursive: boolean = true) {
if (!obj) return
FYGE.Tween.removeTweens(obj);
if (!isRecursive || !obj.children || !obj.children.length) return
obj.children.forEach(child => {
removeTweens(child)
});
}
/**
* 销毁方法
*/
export function destroyAllCtrls() {
destroyToast();
destroyWaiting();
PanelCtrl.instance.destroy();
SceneCtrl.instance.destroy();
}
import { Panel } from "../views/Panel";
import { layers } from "../views/layers";
import { showWaiting, hideWaiting } from "./waitingCtrl";
import { showToast } from "./toastCtrl";
export default class PanelCtrl {
/**
* 父级容器
*/
private _parent: FYGE.Container;
/**
* 半透明黑色背景
*/
private _bg: FYGE.Shape;//FYGE.Graphics;
/**
* 所有的弹框
*/
private stacks: Panel[] = [];
private static _instance: PanelCtrl;
static get instance() {
return PanelCtrl._instance || (PanelCtrl._instance = new PanelCtrl())
}
init(parent: FYGE.Container) {
this._parent = parent;
let bg = new FYGE.Shape();//Graphics()//Shape();
bg.beginFill(0);
bg.drawRect(//引用适配
layers.stageOffsetX - parent.x,
layers.stageOffsetY - parent.y,
layers.stageWidth,
layers.stageHeight
);
bg.endFill();
bg.hitTestByPixel = false;
bg.visible = false;
this._parent.addChild(bg);
this._bg = bg;
}
/**
* 关闭所有弹框
*/
closeAll() {
this.stacks.forEach(e => e.hidePanel());
}
show<T extends Panel>(cls: any, data?: any): T {
showWaiting()
const panel: T = new cls(data);
this.add(panel);
this.stacks.push(panel);
panel.onLoaded = () => {
panel.y = -(1624 - layers.stageHeight >> 1)
hideWaiting();
this.updateView(false);//这里更新不显示动画先,自行判断是否显示
//start只执行一边
panel.start(data);
//如果是最后一个才显示动画
if (panel.visible) panel.showAni();
}
//资源加载失败时
panel.onLoadError = () => {
hideWaiting();
showToast("资源加载失败")
panel.removeEventListener('onDestroy', this.onPanelHide, this);
this.remove(panel);
}
return panel;
}
private bgAni: "hide" | "show";
private updateView(showPanelAni: boolean = true) {
//没有弹框的时候
if (!this.stacks.length) {
// this._bg.visible = false;
// this._current = null;
// this._parent.visible = false;
if (this._bg.visible) {//原先背景存在时,待测试
this.bgAni = "hide"
FYGE.Tween.removeTweens(this._bg);
FYGE.Tween.get(this._bg)
.to({ alpha: 0 }, 200, FYGE.Ease.cubicOut)
.call(() => {
this._bg.visible = false;
this._current = null;
this._parent.visible = false;
})
}
} else {
//显示弹框层
this._parent.visible = true;
if (this.bgAni == "hide") {//如果正在执行蒙层消失动画,
this.bgAni = "show"
FYGE.Tween.removeTweens(this._bg);
this._bg.alpha = 0.7;
}
//如果首次出现弹框,加个动画
if (this._bg.visible === false) {
this._bg.visible = true;
this._bg.alpha = 0;
FYGE.Tween.get(this._bg).to({ alpha: 0.7 }, 200, FYGE.Ease.cubicOut)
}
}
for (let i = 0; i < this.stacks.length; i++) {
if (i < this.stacks.length - 1) {
this.stacks[i].visible = false;
} else {
this.stacks[i].visible = true;
if (showPanelAni) this.stacks[i].showAni();
this._current = this.stacks[i];
}
}
}
/**
* 添加进父级并添加事件
* @param panel
*/
private add(panel: Panel) {
this._parent.addChild(panel);
panel.addEventListener('onDestroy', this.onPanelHide, this);
}
/**
* 移除
* @param panel
*/
private remove(panel: Panel) {
this._parent.removeChild(panel);
this.stacks = this.stacks.filter(e => e != panel);
}
/**
* 弹框移除时执行
* @param e
*/
private onPanelHide(e: FYGE.Event) {
const panel = e.target as Panel;
panel.removeEventListener('onDestroy', this.onPanelHide, this);
this.remove(panel);
this.updateView();
}
//当前弹框
private _current: Panel;
get currentPanel() {
return this._current
}
/**
* 关闭当前弹框
*/
closeCurrent() {
if (this._current) {
this._current.hidePanel();
// this._current.removeEventListener('onDestroy', this.onPanelHide, this);
// this.remove(this._current);
// this.updateView();
}
}
destroy() {
PanelCtrl._instance = null;
this.stacks = null;
this._current = null;
this._parent = null;
FYGE.Tween.removeTweens(this._bg);
this._bg = null;
}
}
\ No newline at end of file
import { Scene } from "../views/Scene";
import { hideWaiting, showWaiting } from "./waitingCtrl";
import { showToast } from "./toastCtrl";
export default class SceneCtrl {
private _parent: FYGE.Container;
private _currentScene: Scene;
private static _instance: SceneCtrl;
static get instance() {
return SceneCtrl._instance || (SceneCtrl._instance = new SceneCtrl())
}
init(parent: FYGE.Container) {
this._parent = parent;
}
change(cls: any, data?: any) {
//如果是同一个场景,考虑是替换还是return
// if (this._currentScene && this._currentScene instanceof cls) return;//new一个得了,playScene维护太蛋疼,到时看性能吧
let scene: Scene = new cls(data);
scene.visible = false;
showWaiting();
let preScene: Scene = this._currentScene;
scene.onLoaded = () => {
hideWaiting();
scene.showAni(() => {
if (preScene) preScene.destroy();
})
scene.visible = true;
//start里可能处理资源信息,所以在onLoaded后执行
scene.start(data);
}
//加载失败,继续用之前的场景,移除scene
scene.onLoadError = () => {
hideWaiting();
showToast("资源加载失败")
this._currentScene = preScene || null;
this._parent.removeChild(scene);
}
this._currentScene = scene;
this._parent.addChild(scene);
}
get currentScene() {
return this._currentScene
}
destroy() {
SceneCtrl._instance = null;
this._currentScene = null;
this._parent = null;
}
}
import { layers } from "../views/layers";
import { RES } from "../RES";
let inited = false;
let _toast: Toast;
let _parent: FYGE.Container;
let startY: number
let endY: number
const initToast = () => {
if (!inited) {
inited = true;
_toast = new Toast();
_parent = layers.toastLayer;
_toast.alpha = 0;
_toast.x = layers.stageOffsetX - _parent.x + (layers.stageWidth - _toast.width) / 2;
var h = _toast.height;
var y = layers.stageOffsetY - _parent.y;
startY = y - h;
endY = y + (layers.stageHeight - h) / 2;
}
}
export const showToast = (msg: string) => {
initToast();
_toast.show(msg)
_parent.addChild(_toast);
FYGE.Tween.removeTweens(_toast);
FYGE.Tween.get(_toast)//动画看需求
.set({ y: startY, alpha: 1 })
.to({ y: endY }, 500, FYGE.Ease.quartOut)
.wait(800)
.to({ alpha: 0 }, 300)
.call(() => {
_parent.removeChild(_toast);
})
}
/**
* 对于之前淘宝小程序遇到的问题,需要销毁,否则会出问题
*/
export const destroyToast = () => {
if (inited && _toast && !_toast.destroyed) {
_toast.destroy();
_toast = null;
_parent = null;
inited = false;
}
}
/**
* toast类,不对外导出,适配居中有问题,有时间改
* 自身居中,
*/
class Toast extends FYGE.Container {
msg: FYGE.TextField;
bg: FYGE.Sprite;
PADDING = 40;
constructor() {
super();
this.mouseChildren = false;
this.mouseEnable = false;
var toastBgTexture: FYGE.Texture = RES.getRes("toastBg.png");
this.bg = new FYGE.Sprite(toastBgTexture);
// this.bg.x = (750 - 460) / 2// (layers.stageWidth - this.bg.width) / 2
this.addChild(this.bg);
this.msg = new FYGE.TextField();
this.msg.size = 28;
this.msg.fillColor = "0xffffff";
this.msg.text = "";
this.msg.verticalAlign = FYGE.VERTICAL_ALIGN.MIDDLE;
this.msg.textHeight = toastBgTexture.height;
this.msg.textAlign = FYGE.TEXT_ALIGN.CENTER;
this.addChild(this.msg)
}
/**
* 显示时调用
* @param msg
*/
show(msg: string) {
this.msg.text = msg;
//文本居中适配
this.msg.x = (this.bg.width - this.msg.textWidth) / 2//(layers.stageWidth - this.msg.textWidth) / 2;
//是否需要根据文本宽度缩放背景
// this.bg.width = Math.min(this.msg.textWidth + this.PADDING * 2, 523);
//背景居中适配,由于上面一行注释,那这行就构造函数里只执行一次吧
// this.bg.x = (layers.stageWidth - this.bg.width) / 2
}
destroy() {
FYGE.Tween.removeTweens(this);
super.destroy();
this.msg = null
this.bg = null;
}
}
\ No newline at end of file
import { RES } from "../RES";
import { layers } from "../views/layers";
import { showAlert } from ".";
let inited = false;
let _waiting: Waiting;
let _parent: FYGE.Container
const initWaiting = () => {
if (!inited) {
inited = true;
const waiting = new Waiting();
_parent = layers.topLayer;
_waiting = waiting;
//居中偏移
var offX = (layers.stageWidth - 160/*_waiting.width*/) / 2;
var offY = (layers.stageHeight - _waiting.height) / 2;
//位置适配
_waiting.x = layers.stageOffsetX - _parent.x + offX;
_waiting.y = layers.stageOffsetY - _parent.y + offY;
//阻止事件用
var bg: FYGE.Graphics = new FYGE.Graphics()
.beginFill(0x000000)
.drawRect(-offX, -offY, layers.stageWidth, layers.stageHeight)
.endFill();
bg.alpha = 0;
_waiting.addChildAt(bg, 0);
}
}
/**
* 显示菊花圈
* @param msg 尽量三个字
*/
export const showWaiting = (msg?: string) => {
initWaiting();
_waiting.show(msg)
_parent.addChild(_waiting);
}
/**
* 隐藏菊花圈
*/
export const hideWaiting = () => {
_parent.removeChild(_waiting);
}
export const destroyWaiting = () => {
if (inited && _waiting && !_waiting.destroyed) {
_waiting.destroy();
_waiting = null;
_parent = null;
inited = false;
}
}
/**
* 菊花圈,有机会重写,应该适应所有场景居中
*/
class Waiting extends FYGE.Container {
msg: FYGE.TextField;
constructor() {
super();
//圆角矩形背景
var rectBgTexture: FYGE.Texture = RES.getRes("waitingBg.png")
var rectBg = new FYGE.Sprite(rectBgTexture);
this.addChild(rectBg);
var rotTexture: FYGE.Texture = RES.getRes("waitingRot.png")
let rot = new FYGE.Sprite(rotTexture);
rot.x = (rectBgTexture.width - rotTexture.width) / 2
rot.y = 47//533;
rot.anchorX = rotTexture.width / 2;
rot.anchorY = rotTexture.height / 2;
this.addChild(rot);
let count = 0;
rot.addEventListener(FYGE.Event.ENTER_FRAME, () => {
count++;
if (count % 30 == 0) rot.rotation += 45;
}, this)
this.msg = new FYGE.TextField();
this.msg.y = 125;
this.msg.textWidth = rectBgTexture.width;
this.msg.textAlign = FYGE.TEXT_ALIGN.CENTER;
this.msg.size = 26
this.msg.fillColor = "#ffffff";
this.addChild(this.msg);
}
show(msg: string = "加载中") {
this.msg.text = msg;
}
destroy() {
super.destroy();
this.msg = null;
}
}
const _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
/**
* base64编码汉字,
* 一般用于链接参数传递,
* 先base64.encode,再encodeURIComponent后带入,取参数时会decodeURIComponent,然后再base64.decode后
* 直接调用Base64.ins
*/
export class Base64 {
// private property
// _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
private static instance: Base64;
public static get ins(): Base64 {
if (!this.instance) {
this.instance = new Base64();
}
return this.instance;
}
constructor() {
}
// public method for encoding
encode(input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = this._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
decode(input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = this._utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
private _utf8_encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
private _utf8_decode(utftext) {
var string = "";
var i = 0;
var c = 0;
var c2 = 0;
var c3 = 0
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}
\ No newline at end of file
/**
* 回收池
*/
export class GPool {
private static pool = {};
/**
* 取出
* @param name
*/
public static takeOut(name: string) {
if (this.pool[name] && this.pool[name].length) {
return this.pool[name].shift();
}
return null;
}
/**
* 回收
* @param name
* @param obj
*/
public static recover(name: string, obj) {
if (!this.pool[name]) {
this.pool[name] = [];
}
this.pool[name].push(obj);
}
}
\ No newline at end of file
/**
* 用到的和业务相关的
* 各种静态方法汇总
*
* 获取修改链接参数
* 获取cookie
* 缓存相关
* 数组相关
*
*/
export class GTool {
/**
* 读取缓存
*/
public static readCache(key: string/*, type: string = 'localStorage'*/) {
//@ts-ignore
return my ? my.getStorageSync({ key: key }).data : localStorage ? localStorage.getItem(key) : null;
// if (!window.localStorage) {
// return false;
// }
// return window[type].getItem(key);
}
/**
* 写缓存
*/
public static writeCache(key: string, value: any = 'true'/*, type: string = 'localStorage'*/) {
//@ts-ignore
my ? my.setStorageSync({ key: key, data: value }) : localStorage && localStorage.setItem(key, value);
// if (!window.localStorage) {
// // trace(Func.replace(SysLang.lang_012, [type]));
// return;
// }
// window[type].setItem(key, value);
}
/**
* 获得cacheKey今日次数
* 第二天归0重新计数
* @param cacheKey
*/
public static returnTodayTimes(cacheKey: string): number {
var year1 = this.readCache("year" + cacheKey);
var month1 = this.readCache("month" + cacheKey);
var day1 = this.readCache("day" + cacheKey);
var date = new Date();
var year2 = date.getFullYear().toString();
var month2 = date.getMonth().toString();
var day2 = date.getDate().toString();
if (this.int(year2) <= this.int(year1)) {
if (this.int(month2) <= this.int(month1)) {
if (this.int(day2) <= this.int(day1)) {
return this.int(this.readCache(cacheKey));
}
}
}
//如果不是同一天了,归0
var today = "0";
this.writeCache("year" + cacheKey, year2);
this.writeCache("month" + cacheKey, month2);
this.writeCache("day" + cacheKey, day2);
this.writeCache(cacheKey, today);
return 0;
}
/**
* 随机,两个参数时是数值范围,比如randomT(1,10),一个参数时是数组
* @param e
* @param n
*/
public static randomT(e, n?) {
return e && "number" == typeof e.length && e.length ? e[Math.floor(Math.random() * e.length)] : ("number" != typeof n && (n = e || 1, e = 0), e + Math.random() * (n - e))
}
/**
* 从数组中移除一个元素
* @param e 元素
* @param arr 数组
*/
public static removeEle(e, arr) {
var index = arr.indexOf(e);
if (index >= 0) {
arr.splice(index, 1)
}
}
/**
* 数组中插入一个数值,按顺序的
* 数组是从小到大的
* @param num
* @param arr
*/
public static insert(num, arr) {
for (var i = arr.length - 1; i >= 0; i--) {
if (num > arr[i]) {
//在arr[i]后加num
arr.splice(i + 1, 0, num);
break
}
}
}
/**
* 获取start到end里的n个整数
* @param start 0
* @param end 19
* @param n 3
*/
public static getRandomNumber(start: number, end: number, n: number): number[] {
var arr = [];
for (var i = 0; i < n; i++) {
var number = Math.floor(Math.random() * (end - start + 1) + start);
if (arr.indexOf(number) < 0) {
arr.push(number);
} else {
i--;
}
}
return arr;
}
/**
* 打乱数字数组,改变原数组
* @param arr
*/
public static disturbNumberArr(arr: number[]) {
arr.sort(function () {
return (0.5 - Math.random());
});
}
public static disturbArr(arr: any[]) {
return arr.sort(function () {
return (0.5 - Math.random());
});
}
/**
* 其实打乱数组取前几个就行
* 随机取数组arr中count个元素,不改变原数组
* @param arr
* @param count
*/
public static getRandomArrayElements(arr: any[], count: number) {
var shuffled = arr.slice(0), i = arr.length, min = i - count, temp, index;
//如果count大于等于数组长度,返回所有数组
if (min <= 0) return shuffled;
if (count <= 0) return [];
//随机排序,然后取出后面的元素
while (i-- > min) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(min);
}
/**
* 随机取数组arr中count个元素,原数组减少count个
* @param arr
* @param count
*/
public static getRandomArrayElementsEx(arr: any[], count: number): any[] {
//如果count大于等于数组长度,返回所有数组
if (arr.length <= count) return arr.slice();
if (count <= 0) return [];
var arrCopy = arr.slice();
var outArr = [];
while (count--) {
var rand = Math.floor(Math.random() * arrCopy.length);
var ele = arrCopy.splice(rand, 1)[0];
outArr.push(ele);
}
return outArr
}
/**
* 向下取整,或把字符串执行parseInt(字符串转数字取整数部分)
* @param n 数字或字符串
*/
private static int(n: any): number {
return n >> 0;//~~n
};
/**
* emoji正则式
*/
public static emojiReg = /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/ig
/**
* 在字符串间加空格
* @param str
*/
public static addSpaceInString(str: string) {
if (!str.length || str.length == 1) return str;
var txt = "";
//每个字符后加空格
for (var i = 0; i < str.length - 1; i++) {
txt = txt + str[i] + " ";
}
txt = txt + str[str.length - 1]
return txt
}
/**
* 毫秒剩余时间转成时分秒
* 1小时1分1秒
* @param timeStamp
*/
public static getShiFenMiaoByTimeStamp(timeStamp: number) {
var hours: any = Math.floor((timeStamp % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes: any = Math.floor((timeStamp % (1000 * 60 * 60)) / (1000 * 60));
// var seconds: any = (timeStamp % (1000 * 60)) / 1000;
var seconds: any = Math.floor((timeStamp % (1000 * 60)) / 1000);
hours = hours < 10 ? ('0' + hours) : hours;
minutes = minutes < 10 ? ('0' + minutes) : minutes;
seconds = seconds < 10 && seconds >= 1 ? ('0' + seconds) : seconds;
// return hours + " :" + minutes + " :" + seconds;
return hours + "小时" + minutes + "分" + seconds + "秒";
}
/**
* 获取字符串真实长度,中文算两个
* @param str
*/
static getRealStringLength(str: string): number {
var realLength = 0, len = str.length, charCode = -1;
for (var i = 0; i < len; i++) {
charCode = str.charCodeAt(i);
if (charCode >= 0 && charCode <= 128) realLength += 1;
else realLength += 2;
}
return realLength;
}
/**
* 切字符串
* @param str
* @param realLength
* @param tailStr
*/
static cutStringAcoRealLength(str: string, limit: number, tailStr: string = "...") {
let length = 0;
let out = "";
for (let i of str) {
let charCode = i.charCodeAt(0);
if (charCode >= 0 && charCode <= 128) length += 1;
else length += 2;
if (length <= limit) {
out = out.concat(i);
} else {
out = out.concat(tailStr);
break;
}
}
return out;
}
}
\ No newline at end of file
/////这里集成一些只有web环境才会用到的方法,链接参数,cookie参数等等
let urlParams: { [key: string]: string | true };
/**
* 获取链接参数
* @param key
*/
export function getUrlParams(key: string): string | true {
if (urlParams) return urlParams[key];
urlParams = {};
let search = window.location.search;
try {
search = top.location.search; //尝试获取顶层的链接
} catch (e) {
}
//获取链接参数
for (let item of search.replace('?', '').split('&')) {
let arr = item.split('=');
urlParams[arr[0]] = arr.length === 1 ? true : decodeURIComponent(arr[1]);
}
return urlParams[key];
}
export const duiba_md5 = (function (/*$*/) {
// function safe_add(x, y) {
// var lsw = (x & 65535) + (y & 65535), msw = (x >> 16) + (y >> 16) + (lsw >> 16);
// return (msw << 16) | (lsw & 65535)
// }
function bit_rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
function md5_cmn(q, a, b, x, s, t) {
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
}
function md5_ff(a, b, c, d, x, s, t) {
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)
}
function md5_gg(a, b, c, d, x, s, t) {
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)
}
function md5_hh(a, b, c, d, x, s, t) {
return md5_cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t)
}
function binl_md5(x, len) {
x[len >> 5] |= 128 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var i, olda, oldb, oldc, oldd, a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
for (i = 0; i < x.length; i += 16) {
olda = a;
oldb = b;
oldc = c;
oldd = d;
a = md5_ff(a, b, c, d, x[i], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i], 20, -373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i], 11, -358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i], 6, -198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd)
}
return [a, b, c, d]
}
function binl2rstr(input) {
var i, output = "";
for (i = 0; i < input.length * 32; i += 8) {
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 255)
}
return output
}
function rstr2binl(input) {
var i, output = [];
output[(input.length >> 2) - 1] = undefined;
for (i = 0; i < output.length; i += 1) {
output[i] = 0
}
for (i = 0; i < input.length * 8; i += 8) {
output[i >> 5] |= (input.charCodeAt(i / 8) & 255) << (i % 32)
}
return output
}
function rstr_md5(s) {
return binl2rstr(binl_md5(rstr2binl(s), s.length * 8))
}
function rstr_hmac_md5(key, data) {
var i, bkey = rstr2binl(key), ipad = [], opad = [], hash;
ipad[15] = opad[15] = undefined;
if (bkey.length > 16) {
bkey = binl_md5(bkey, key.length * 8)
}
for (i = 0; i < 16; i += 1) {
ipad[i] = bkey[i] ^ 909522486;
opad[i] = bkey[i] ^ 1549556828
}
hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
return binl2rstr(binl_md5(opad.concat(hash), 512 + 128))
}
function rstr2hex(input) {
var hex_tab = "0123456789abcdef", output = "", x, i;
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 15) + hex_tab.charAt(x & 15)
}
return output
}
function str2rstr_utf8(input) {
return unescape(encodeURIComponent(input))
}
function raw_md5(s) {
return rstr_md5(str2rstr_utf8(s))
}
function hex_md5(s) {
return rstr2hex(raw_md5(s))
}
function raw_hmac_md5(k, d) {
return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))
}
function hex_hmac_md5(k, d) {
return rstr2hex(raw_hmac_md5(k, d))
}
var duiba_md5 = function (string, key?, raw?) {
if (!key) {
if (!raw) {
return hex_md5(string)
} else {
return raw_md5(string)
}
}
if (!raw) {
return hex_hmac_md5(key, string)
} else {
return raw_hmac_md5(key, string)
}
};
var hexcase = 0;
var b64pad = "";
var chrsz = 8;
// $.extend({
// duiba_b64_sha: function (input) {
// return binb2b64(core_sha1(str2binb(input), input.length * chrsz))
// }
// });
function core_sha1(x, len) {
x[len >> 5] |= 128 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for (var j = 0; j < 80; j++) {
if (j < 16) {
w[j] = x[i + j]
} else {
w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1)
}
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde)
}
return Array(a, b, c, d, e)
}
function sha1_ft(t, b, c, d) {
if (t < 20) {
return (b & c) | ((~b) & d)
}
if (t < 40) {
return b ^ c ^ d
}
if (t < 60) {
return (b & c) | (b & d) | (c & d)
}
return b ^ c ^ d
}
function sha1_kt(t) {
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514
}
function core_hmac_sha1(key, data) {
var bkey = str2binb(key);
if (bkey.length > 16) {
bkey = core_sha1(bkey, key.length * chrsz)
}
var ipad = Array(16), opad = Array(16);
for (var i = 0; i < 16; i++) {
ipad[i] = bkey[i] ^ 909522486;
opad[i] = bkey[i] ^ 1549556828
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160)
}
function safe_add(x, y) {
var lsw = (x & 65535) + (y & 65535);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 65535)
}
function rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
function str2binb(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz) {
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i % 32)
}
return bin
}
function binb2str(bin) {
var str = "";
var mask = (1 << chrsz) - 1;
for (var i = 0; i < bin.length * 32; i += chrsz) {
str += String.fromCharCode((bin[i >> 5] >>> (32 - chrsz - i % 32)) & mask)
}
return str
}
function binb2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 15) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 15)
}
return str
}
function binb2b64(binarray) {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var str = "";
for (var i = 0; i < binarray.length * 4; i += 3) {
var triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 255) << 16) | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 255) << 8) | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 255);
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 > binarray.length * 32) {
str += b64pad
} else {
str += tab.charAt((triplet >> 6 * (3 - j)) & 63)
}
}
}
str = str + "=";
return str
}
// window.duiba_md5 = duiba_md5;
return duiba_md5
}(/*Zepto*/));
\ No newline at end of file
///////////////////时间相关的方法放这里
/**
* 判断当前时间是否在指定时间区间内,每日,注意没判断起始时间是否肯定小于结束时间
* @param beginTime 形如"9:30","09:30",起始时间
* @param endTime 形如"21:30",结束时间
*/
export function checkAuditDayTime(beginTime: string, endTime: string): boolean {
return !checkBeforeDayTime(beginTime) && checkBeforeDayTime(endTime)
}
/**
* 判断当前时间是否在给定时间前,每天
* 精确到分,有需要自行改造截取方法和setHours传参
* @param time 形如"11:30","09:30",小时 0(午夜) ~ 23(晚上11点),分0 ~ 59 之间,负数或超出,会进行进制换算
* @returns 返回true表示当前时间小于传入时间,即未到传入时间
*/
export function checkBeforeDayTime(time: string): boolean {
var nowDate = new Date();
var timeDate = new Date(nowDate);
var index = time.lastIndexOf("\:");
var hour = time.substring(0, index);
var minue = time.substring(index + 1, time.length);
timeDate.setHours(+hour, +minue, 0, 0);
return nowDate.getTime() < timeDate.getTime()
}
/**
* 毫秒剩余时间转成时分秒,具体格式自行修改
* 01时01分01秒
* @param timeStamp
*/
export function getShiFenMiaoByTimeStamp(timeStamp: number): string {
var hours: any = Math.floor((timeStamp % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes: any = Math.floor((timeStamp % (1000 * 60 * 60)) / (1000 * 60));
var seconds: any = Math.floor((timeStamp % (1000 * 60)) / 1000);
hours = hours < 10 ? ('0' + hours) : hours;
minutes = minutes < 10 ? ('0' + minutes) : minutes;
seconds = seconds < 10 ? ('0' + seconds) : seconds;
// return hours + ":" + minutes + ":" + seconds;
return hours + "时" + minutes + "分" + seconds + "秒";
}
/**
* 根据时间戳返回各种格式,自行修改,到时加枚举
* @param timeStamp 时间戳
* @return 20190606 09:05:33 2019-06-06 09:05:33 2019/06/06 09:05:33 2019年3月12日10时9分29秒
*/
export function getDateTime(timeStamp: number): string {
function add0(m: number) {
return m < 10 ? '0' + m : m
}
var time = new Date(timeStamp);
var y = time.getFullYear();
var m = time.getMonth() + 1;
var d = time.getDate();
var h = time.getHours();
var mm = time.getMinutes();
var s = time.getSeconds();
// return "" + y + add0(m) + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s);
// return "" + y + '-' + add0(m) + '-' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s);
// return "" + y + '/' + add0(m) + '/' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s);
return y + "年" + m + '月' + d + '日' + h + '时' + mm + '分' + s + '秒'
}
/**
* 日期格式转时间戳
* 时间格式得用/,ios用-有问题,"2019/06/17 00:00:00",,,,ios也不能直接用Number(new Date())
* @param date "2019/06/17 00:00:00" "2019-06-17 00:00:00"
*/
export function getTimeStampByDate(date: string) {
return new Date(date.replace(/-/g, "/")).getTime();
}
/**
* 快速获取年月日时分秒 "2021-02-01 18:32:32"
* @param timeStamp 不传表示当前
*/
export function getDate(timeStamp: number = Date.now()): string {
//有局限性,但是无妨 19暂时年份不会超
return new Date(timeStamp + 8 * 3600 * 1000).toJSON().substr(0, 19).replace("T", " ");
}
/**
* 判断两个时间戳是否为同一天
* @param time1
* @param time2
*/
export function checkSameDay(time1: number, time2: number): boolean {
return new Date(time1).toDateString() === new Date(time2).toDateString()
}
import { ajax } from "../ajax";
// sdk 不能加crossorign
// <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
// 小程序分享得用这个
// <script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
/**
* 判断是否是微信环境
*/
export function isWxClient() {
var ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) && ua.match(/MicroMessenger/i)[0] == "micromessenger") {
return true;
}
return false;
};
/**
* 初始化微信分享配置
*/
export function initWxConfig(callback?: (s: boolean) => void, debug: boolean = false) {
if (!isWxClient()) {
callback && callback(false)
return;
}
//微信分享,获取分享签名
ajax({
type: 'GET',
url: '/wechatShare/getShareInfo/v2',
data: { url: window.location.href },//有问题再检查链接//部分链接参数会导致初始化失败,以后中文参数用base,%用自定字符替换
dataType: 'json',
success: function (data) {
if (data.success) {
console.log("微信配置获取:")
window["wx"].config({
debug,
appId: data.wxappid,
timestamp: data.wxtimestamp,
nonceStr: data.wxnonceStr,
signature: data.wxsignature,
jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'chooseImage']
});
callback && callback(true)
} else {
callback && callback(false)
}
},
error: function (data) {
callback && callback(false)
}
});
}
/**
* 初始化分享信息
* @param title 标题
* @param desc 描述,朋友圈无
* @param link 主域名一致的链接,且是https
* @param imgUrl 图片必须是https
*/
export function initWxShare(
title: string,
desc: string,
link: string,
imgUrl: string
) {
//执行ready可重新设置分享信息
window["wx"].ready(function () {
window["wx"].onMenuShareTimeline({
title,
link,
imgUrl,
success: function (res) {
}
});
//监听“分享给朋友”按钮点击、自定义分享内容及分享结果接口
window["wx"].onMenuShareAppMessage({
title,
desc,
link,
imgUrl,
success: function (res) {
}
});
})
}
//模拟下$ TODO
// 或者引个zepto
// <script crossorigin="anonymous" src="//yun.duiba.com.cn/db_games/libs/zepto_security_downloadApp.min.js"></script>
//易盾的sdk
// <script type="text/javascript" src="//cstaticdun.126.net/load.min.js"></script> -->
var $ = window["$"]
/**
* @note 极验 - 第三方插件
* @author 张晨辰
* @email zcc@duiba.com.cn
* @create 2017-04-19 12:01:45
* @update 2017-06-28 10:06:00
* @des https://www.163yun.com/help/documents/294963579379175424
* @dependencies <script type="text/javascript" src="//c.dun.163yun.com/js/c.js"></script>
* 2.0 <script src="//cstaticdun.126.net/load.min.js"></script> 用下面这个
*/
let captchaIns;
export function initNECaptcha(options) {
if (!options.captchaId) {
return false;
}
$('body').append('<div class="captcha"><div id="check_wrapper" class="neCaptcha-dialog"></div></div>');
var opts = {
element: '#check_wrapper', // 可以是验证码容器id,也可以是HTMLElement
captchaId: options.captchaId, // 这里填入申请到的验证码id
width: options.width || 270, // 验证码组件显示宽度
mode: options.mode || 'embed',
onVerify: function (err, data) {
if (!err) {
$(".captcha").unbind("click");
$('.captcha').remove();
// data.validate = base64.encode(data.validate);
options.callback && options.callback(data);
}
}
}
window["initNECaptcha"] && window["initNECaptcha"](opts, function (instance) {
captchaIns = instance
$(".captcha").click(function (e) {
if (e.target.className == "captcha") {
if (captchaIns) captchaIns.refresh()
}
});
}, function (err) {
console.log(err, 55655665)
//初始化失败,点击黑色区域重新初始
$(".captcha").click(function (e) {
// if (e.target.className == "captcha") {
$(".captcha").unbind("click");
$('.captcha').remove();
initNECaptcha(options)
// }
});
});
window["loading"] && window["loading"].close();
$('.captcha').show();
};
//例子
initNECaptcha({
captchaId: /*Tools.captchId*/111, //a869bfdfb9bd4cdf88e1ff2f8667a114
callback: function (ret) {
console.log(ret.validate)
}
})
/* 易盾css*/
.captcha {
display: none;
position: fixed;
z-index: 10000;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.6);
}
.captcha .neCaptcha-dialog {
background-color: #fff;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.35);
-webkit-box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.35);
position: absolute;
left: 50%;
top: 45%;
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
width: 270px;
height: 134px;
}
.captcha .neCaptcha-dialog::after {
position: absolute;
content: '单次游戏结束,请拖动滑块提交分数';
width: 100%;
height: 30px;
top: -40px;
left: 0;
text-align: center;
line-height: 30px;
font-size: 16px;
color: #ffff00;
}
.captcha .neCaptcha-dialog::before {
background-color: #fff;
content: '';
display: block;
width: 280px;
height: 144px;
position: absolute;
top: -5px;
left: -5px;
z-index: -1;
}
\ No newline at end of file
import { RES } from "../RES";
/**
* 暂时用列表的接口
*/
export class Item extends FYGE.Container implements FYGE.IScrollListItem {
get skinName(): string { return null };
constructor(data?) {
super();
if (this.skinName) RES.initSkinDisplay(this, this.skinName, this);
/*setTimeout(() => {*/ this.initUi(data); /*})*///考虑是否可以不加延时,加了会有问题,自行调用的updateData会先执行,不加的话继承类里initUi里的属性。。。
}
/**
* 自定义的初始布局方法
* 注意声明的变量会覆盖initUi里赋值的变量,
*/
initUi(data?) {
}
/**
* 自行调用的更新数据方法
*/
updateData(data?) {
}
/**
* 滚动列表的数据更新方法
* @param id
* @param data
*/
initData(id: number, data: any): void {
this.id = id;//这两个直接赋值吧
this.data = data;
this.resetData();
}
id: number;
data: any;
/**
* 滚动列表ScrollList里专用
* 重置item里属性及显示对象属性的方法,
* 在每次initData会调用
*/
resetData() {
}
}
import { RES } from "../RES";
import { removeTweens } from "../ctrls";
/**
*
*/
export class Module extends FYGE.Container {
protected data: any;
constructor(data?: any) {
super();
this.data = data;
this.init();
}
/**
* 初始化资源和皮肤
*/
private init() {
this.preLoadRes().then(
() => {
//添加皮肤配置
if (this.skinName) RES.initSkinDisplay(this, this.skinName, this);
this.initUi();
this.onLoaded && this.onLoaded();
},
() => {
this.onLoadError && this.onLoadError();
}
);
}
/**
* 提前加载的资源
*/
protected preLoadRes() {
return new Promise<void>((resolve, reject) => {
if (this.groupNames && this.groupNames.length) {
var arr: Promise<any>[] = [];
for (var i = 0; i < this.groupNames.length; i++) {
arr.push(RES.loadGroup(this.groupNames[i]))
}
// @ts-ignore
Promise.all(arr).then(resolve, reject)
} else {
resolve()
}
})
}
/**
* 初始化ui
* 子类修改
*/
protected initUi() {
}
/**
* 资源加载完成后执行,用于场景及弹框控制
*/
onLoaded: () => void
/**
* 资源加载失败时执行,用于场景及弹框控制
*/
onLoadError: () => void;
/**
* 可以有多个组
*/
get groupNames(): string[] { return null }
/**
* 皮肤名字
*/
get skinName(): string { return null };
/**
* 在构造函数后执行
*/
start(data?: any) {
this.initEvents();
}
/**
* 添加事件
*/
initEvents(): void {
}
/**
* 移除事件
*/
removeEvents(): void {
}
/**
* 鼠标事件
* @param enable
*/
protected enableMouseEvt(enable: boolean): void {
this.mouseEnable = enable;
this.mouseChildren = enable;
}
/**
* 延时防连点
* @param target
* @param {number} delay
*/
protected btnDelay(target, delay = 2000) {
target.mouseEnable = false;
target.mouseChildren = false;
setTimeout(() => {
target.mouseEnable = true;
target.mouseChildren = true;
}, delay);
}
public destroy(): void {
//以防有些地方用了showAni
removeTweens(this);
// this.data = null;//看情况吧,有时候hidePanel后用了data,注意,还是先去掉吧
//移除事件
this.removeEvents();
//派发销毁事件,主要用于场景及弹框控制
this.dispatchEvent("onDestroy");
super.destroy();
}
}
import { Module } from "./Module";
export class Panel extends Module {
protected isShowing: boolean
showAni() {
if (this.isShowing) return;
this.isShowing = true;
let oriY = this.y || 0;
this.y = -200;
FYGE.Tween.get(this)
.to({y: oriY}, 500, FYGE.Ease.quartOut)
.call(() => {
this.isShowing = false;
})
}
initEvents() {
this.closeBtns.forEach(
btn => {
if (btn) btn.addEventListener(FYGE.MouseEvent.CLICK, this.hidePanel, this)
}
)
}
removeEvents() {
this.closeBtns.forEach(
btn => {
if (btn) btn.removeEventListener(FYGE.MouseEvent.CLICK, this.hidePanel, this)
}
)
}
/**
* 需要的放入,不重复写关闭按钮事件
*/
protected get closeBtns(): any[] {
return [this['closeBtn']]
}
hidePanel() {
this.destroy();
}
}
import { Module } from "./Module";
export class Scene extends Module {
/**
* 显示动画
* 继承时注意,回调要加
* 因为这种动画基本原场景最好不消失
*/
showAni(callback: Function) {
callback()
}
/**
* 统一更新方法
*/
updateScene() {
}
}
\ No newline at end of file
import PanelCtrl from "../ctrls/panelCtrl";
import SceneCtrl from "../ctrls/sceneCtrl";
/**
* 添加进舞台的所有层级
* 仿白鹭的那套
*/
class Layers extends FYGE.Container {
private _bottomLayer: FYGE.Container;
private _sceneLayer: FYGE.Container;
private _popupLayer: FYGE.Container;
private _toastLayer: FYGE.Container;
private _topLayer: FYGE.Container;
private _shareLayer: FYGE.Container;
init(stage: FYGE.Stage) {
stage.addChild(this);
const arr = [
"_bottomLayer",
"_sceneLayer",
"_popupLayer",
"_toastLayer",
"_topLayer",
"_shareLayer"
];
for (let i = 0; i < arr.length; i++) {
this[arr[i]] = new FYGE.Container();
//有些时候,定宽的时候,部分layer置顶,部分居中,再处理
//为了都置顶和置左,stage的方式永远居中视窗,要么改stage永远左上为00
// this[arr[i]].y = this.stageOffsetY;
//如果定宽这里没必要,肯定是0
// this[arr[i]].x = this.stageOffsetX;//去掉,定高时就居中了
this.addChild(this[arr[i]]);
}
//都以顶部适配
// this.sceneLayer.y = this.stageOffsetY;
// this.popupLayer.y = this.stageOffsetY;
//都以底部适配
// this.sceneLayer.y = -this.stageOffsetY;
// this.popupLayer.y = -this.stageOffsetY;
//这个因为psd弹框不规范
// this.popupLayer.y -= 420 / 2;
this.shareLayer.y = -this.stageOffsetY;
//初始化场景层级
SceneCtrl.instance.init(this.sceneLayer);
//初始化弹框层级
PanelCtrl.instance.init(this.popupLayer);
}
/**
* 底图所在层级,比如统一的背景
*/
get bottomLayer() { return this._bottomLayer }
/**
* 场景
*/
get sceneLayer() { return this._sceneLayer }
/**
* 弹框
*/
get popupLayer() { return this._popupLayer }
/**
* toast所在层级
*/
get toastLayer() { return this._toastLayer }
/**
* 顶层,比如统一标题栏等
*/
get topLayer() { return this._topLayer }
/**
* 分享引导层
*/
get shareLayer() { return this._shareLayer }
/**
* 舞台信息都放在layers里吧
* 舞台可见高度,初始化后才能使用
*/
get stageHeight() {
if (!this.stage) return 0;
return this.stage.viewRect.height;
}
/**
* 舞台可见宽度
*/
get stageWidth() {
if (!this.stage) return 0;
return this.stage.viewRect.width;
}
/**
* 适配方式x两边偏移的量,固定宽度x为0
*/
get stageOffsetX() {
if (!this.stage) return 0;
return this.stage.viewRect.x;
}
get stageOffsetY() {
if (!this.stage) return 0;
return this.stage.viewRect.y;
}
/**
* 舞台中心点位置x
*/
// get stageCenterX(): number {
// return this.stage.viewRect.x + this.stage.viewRect.width >> 1;
// }
/**
* 舞台中心点位置y,layer位置做过偏移的就不对了,所以还是自行算吧
*/
// get stageCenterY(): number {
// return this.stage.viewRect.y + this.stage.viewRect.height >> 1;
// }
}
export const layers = new Layers();
//先执行,在淘宝小程序中重新进入会再次初始化
export function destroyLayers() {
//所有层级移除,init会重新建
layers.removeChildren();
//从父级stage移除自己,init会重新加
if (layers.parent) layers.parent.removeChild(layers)
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "receive_game",
"version": "1.0.0",
"description": "接红包基础模版",
"main": "released/output.js",
"module": "released/output.module.js",
"useAsModule": false,
"scripts": {
"dev": "node rollup.dev.mjs -p 8080",
"test": "cd test && npm run testDev",
"build": "npm run handleRes && node scripts/mergeJson && node scripts/upload && npm run buildTS",
"buildTS": "rollup -c rollup.prod.mjs && node scripts/uploadSingleJs",
"handleLotS": "node scripts/handleLotS",
"handleRes": "node scripts/delRel && node scripts/copyRes && node scripts/createTm && node scripts/textureMerge && node scripts/delTm && node scripts/imageMin",
"copyJs": "node scripts/copyJs",
"flushRes": "node scripts/flushRes",
"psd": "node scripts/psdH && node scripts/flushRes",
"psdSin": "node scripts/psdHSin",
"clearSameImg": "node scripts/clearSameImg && node scripts/flushRes",
"createModule": "node scripts/createModule",
"createAllModule": "node scripts/createAllModule"
},
"devDependencies": {
"@babel/core": "^7.18.2",
"@babel/preset-env": "^7.18.2",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.1.1",
"@rollup/plugin-typescript": "^8.3.0",
"address": "^1.2.0",
"ali-oss": "^4.11.4",
"chalk": "^2.3.0",
"co": "^4.6.0",
"del": "^2.2.1",
"duiba-utils": "^1.0.9",
"form-data": "^4.0.0",
"fs": "0.0.2",
"glslify": "^7.1.1",
"md5": "^2.3.0",
"path": "^0.12.7",
"progress": "^2.0.0",
"psd": "^3.2.0",
"readline": "^1.3.0",
"rollup": "^2.61.1",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-glsl-loader": "^1.0.13",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-progress": "^1.1.2",
"rollup-plugin-serve": "^1.1.0",
"rollup-plugin-terser": "^7.0.2",
"tslint": "^5.9.1",
"typescript": "^4.5.4",
"javascript-obfuscator": "^4.1.0",
"texture-packer-hycv": "^1.1.1"
},
"author": "haiyoucuv",
"license": "ISC"
}
{
"type": "activity",
"name": "template"
}
\ No newline at end of file
{
"groups": [
{
"keys": "comCloseBtn.png,toastBg.png,waitingBg.png,waitingRot.png",
"name": "common"
},
{
"keys": "coin.svga,fudai.png,点中红包飘爱心.svga,点中飘金币.svga,红包1.png,红包2.png,红包3.png,金币.png",
"name": "game"
}
],
"path": "./resource/"
}
\ No newline at end of file
{
"x": 0,
"y": 0,
"type": "container",
"children": [
]
}
/**
* rollup.dev.mjs
* Created by 还有醋v on 2022/9/19 下午6:10.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
import address from "address";
import chalk from 'chalk';
import * as fs from "fs";
import * as path from "path";
import * as rollup from "rollup";
import json from "@rollup/plugin-json";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import commonjs from "rollup-plugin-commonjs";
import glslLoader from "rollup-plugin-glsl-loader";
import livereload from "rollup-plugin-livereload";
import progress from "rollup-plugin-progress";
import serve from "rollup-plugin-serve";
import BannerVariable from "./config/plugins/BannerVariable/index.mjs";
import { _debounce, runScript } from "./config/utils/utils.mjs";
import { flushRes } from "./scripts/flushRes.js";
const argv = process.argv;
const port = +argv[argv.indexOf("-p") + 1] || 8080;
const open = +argv[argv.indexOf("-open") + 1] || false;
const { version } = JSON.parse(fs.readFileSync("./package.json", "utf-8"));
watchResChange();
const options = {
input: "src/index.ts",
cache: true,
output: [
{
file: "debug/output.js",
format: "umd",
name: "output",
sourcemap: true,
},
{
file: 'debug/output.module.js',
format: 'esm',
sourcemap: true,
}
],
onwarn(warning) {
if (warning.code !== 'CIRCULAR_DEPENDENCY') {
console.log(chalk.red(`\n(!) ${warning.message}`));
}
},
plugins: [
progress(),
BannerVariable({
values: {
__ENV__: JSON.stringify(process.env.NODE_ENV || 'development'),
__version__: JSON.stringify(version),
__buildDate__: JSON.stringify(new Date()),
process: JSON.stringify({env: {RUNTIME: "web"}}),
// a: `eval(function(c,g,a,b,d,e){d=String;if(!"".replace(/^/,String)){for(;a--;)e[a]=b[a]||a;b=[function(f){return e[f]}];d=function(){return"\\\\w+"};a=1}for(;a--;)b[a]&&(c=c.replace(new RegExp("\\\\b"+d(a)+"\\\\b","g"),b[a]));return c}('(()=>{1 0(){2(()=>{3("4")()},5)}6{0()}7(8){}})();',9,9,"block function setInterval Function debugger 50 try catch err".split(" "),0,{}));`,
}
}),
typescript({ tsconfig: "./tsconfig.json", sourceMap: true }),
resolve({ jsnext: true, preferBuiltins: true, browser: true }),
commonjs(),
json(),
glslLoader({
glslify: true,
}),
serve({
port,
open,
headers: {
'Access-Control-Allow-Origin': '*',
},
verbose: false,
}),
livereload({
verbose: false,
}),
],
};
const watcher = rollup.watch(options);
watcher.on("event", (event) => {
switch (event.code) {
case "START":
console.clear();
break;
case "END":
console.log(`http://localhost:${port} -> ${path.resolve(".")}`);
console.log(`http://${address.ip()}:${port} -> ${path.resolve(".")}`);
console.log(chalk.green("LiveReload enabled"));
break;
}
});
/**
* 资源变化自动刷新
*/
function watchResChange() {
const skinUrl = "./resource/skin.json";
fs.watchFile(skinUrl, { persistent: true, interval: 2000 }, () => {
const skinDataAll = fs.readFileSync(skinUrl)
const endFile = `export const SkinJson = ${skinDataAll}`;
fs.writeFileSync("./src/SkinJson.ts", endFile);
console.log("SkinJson.ts文件已更新");
});
// 修改resource文件夹任意内容自动刷新资源
const flushScript = path.resolve('./scripts/flushRes.js');
fs.watch('./resource/', { recursive: true }, _debounce((event, filename) => {
if (
filename === ".DS_Store"
|| filename === "res.json"
|| filename === "skin.json"
) return;
flushRes(`http://${address.ip()}:${port}`);
// runScript(flushScript, (err) => err && console.error(err));
}));
// runScript(flushScript, (err) => err && console.error(err));
flushRes(`http://${address.ip()}:${port}`);
}
/**
* rollup.prod.mjs
* Created by 还有醋v on 2022/9/19 下午6:10.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
import json from "@rollup/plugin-json";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import fs from "fs";
import commonjs from "rollup-plugin-commonjs";
import glslLoader from "rollup-plugin-glsl-loader";
import progress from "rollup-plugin-progress";
import { terser } from "rollup-plugin-terser";
import BannerVariable from "./config/plugins/BannerVariable/index.mjs";
import babel from "@rollup/plugin-babel";
// import obfuscatorPlugin from './config/plugins/rollup-plugin-javascript-obfuscator.mjs'
const { version } = JSON.parse(fs.readFileSync("./package.json", "utf-8"));
export default {
input: "src/index.ts",
output: [
{
file: "released/output.js",
format: "umd",
name: "output",
sourcemap: true,
},
{
file: 'released/output.module.js',
format: 'esm',
sourcemap: true,
}
],
plugins: [
progress(),
BannerVariable({
values: {
__ENV__: JSON.stringify(process.env.NODE_ENV || 'prod'),
__version__: JSON.stringify(version),
__buildDate__: JSON.stringify(new Date()),
process: JSON.stringify({ env: { RUNTIME: "web" } })
}
}),
babel.babel({
exclude: "node_modules/**",
presets: [
[
"@babel/preset-env",
{
modules: false,
useBuiltIns: "usage",
}
]
],
babelHelpers: "runtime"
}),
resolve({ jsnext: true, preferBuiltins: true, browser: true }),
commonjs(),
typescript({ tsconfig: "./tsconfig.json", sourceMap: false, watch: false, }),
json(),
glslLoader({
glslify: true,
}),
terser(),
// obfuscatorPlugin({
// // 疯狂debug
// debugProtection: true,
// debugProtectionInterval: 4000,
//
// // 单行输出
// compact: true,
//
// // 自卫模式,美化代码就无法运行
// selfDefending: true,
//
// // 扁平化控制流
// controlFlowFlattening: true,
// controlFlowFlatteningThreshold: 0.3,
//
// // 注入死代码
// deadCodeInjection: true,
// deadCodeInjectionThreshold: 0.2,
//
// // 标识符名称生成器
// // hexadecimal 16进制 包体增大较多
// // mangled 短名称
// // mangled-shuffled 与mangled相同,但带有洗牌字母表
// identifierNamesGenerator: 'mangled-shuffled',
//
// // 数字转表达式 如:
// // const foo = 1234;
// // const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
// // numbersToExpressions: true,
//
// log: true,
//
// // 拆分字面字符串
// splitStrings: true,
//
// stringArray: true,
// rotateStringArray: true,
// stringArrayCallsTransform: true,
// stringArrayCallsTransformThreshold: 1,
// stringArrayThreshold: 1,
// stringArrayEncoding: ["none", "base64"],
// stringArrayWrappersParametersMaxCount: 5,
//
// // transformObjectKeys: true,
// target: "browser",
// }),
]
};
var fs = require("fs");
var path = require('path');
var del = require('del');
var pathName = "./resource";
var inPath = "./resource/common/";
{
key: ["aa", "bb"]
}
var hash = {};//记录名字和所在文件夹
var files = fs.readdirSync(pathName);
files.forEach(function (file) {
//文件common,不处理
if (file == "common") return
//路径
let fPath = path.join(pathName, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
var sonFiles = fs.readdirSync(fPath);
//没有文件
if (!sonFiles.length) return;
sonFiles.forEach(function (s) {
if (!hash[s]) hash[s] = [];
hash[s + ""].push(file);
})
}
})
//遍历
for (var key in hash) {
//有重复的,拷贝到common,删除原文件夹里的文件,
if (hash[key].length > 1) {
// 拷贝到common
fs.writeFileSync(inPath + key, fs.readFileSync(pathName + "/" + hash[key][0] + "/" + key));
console.log("重复资源:" + key)
//删除原文件夹里的文件,
hash[key].forEach(function (s) {
del(pathName + "/" + s + "/" + key)
})
}
}
console.log("重复资源处理完成")
\ No newline at end of file
var fs = require("fs");
// fs.writeFileSync(
// "./released/output.js",
// fs.readFileSync("./output.js")
// )
// var endPath = 'D:/duibaGame/测试项目0527/taobaominiTest/client/pages/index1/';
var endPath = 'D:/duibaGame/淘宝项目/taobao_mini/babycare_xiaoxiaole/babycare_c_client/client/pages/index/';
var version = Math.round(new Date().getTime() / 1000);
// fs.writeFileSync(endPath + "output." + version + ".js", fs.readFileSync("./released/output.js"));
fs.writeFileSync(endPath + "output.js", fs.readFileSync("./released/output.js"));
// console.log("js覆盖完成")
console.log(`版本号:
${version}`)
// cp infile outfile 拷贝文件直接放指令里
\ No newline at end of file
var fs = require('fs');
var path = require("path");
function writeFile(p, text) {
fs.writeFile(p, text, function (err) {
// if (!err)
// console.log("写入成功!")
})
}
//递归创建目录 同步方法
function mkdirsSync(dirname) {
if (fs.existsSync(dirname)) {
return true;
} else {
if (mkdirsSync(path.dirname(dirname))) {
// console.log("mkdirsSync = " + dirname);
fs.mkdirSync(dirname);
return true;
}
}
}
function _copy(src, dist) {
var paths = fs.readdirSync(src)
paths.forEach(function (p) {
var _src = src + '/' + p;
var _dist = dist + '/' + p;
var stat = fs.statSync(_src)
if (stat.isFile()) {// 判断是文件还是目录
fs.writeFileSync(_dist, fs.readFileSync(_src));
} else if (stat.isDirectory()) {
copyDir(_src, _dist)// 当是目录是,递归复制
}
})
}
/*
* 复制目录、子目录,及其中的文件
* @param src {String} 要复制的目录
* @param dist {String} 复制到目标目录
*/
function copyDir(src, dist) {
var b = fs.existsSync(dist)
// console.log("dist = " + dist)
if (!b) {
// console.log("mk dist = ",dist)
mkdirsSync(dist);//创建目录
}
// console.log("_copy start")
_copy(src, dist);
}
function createDocs(src, dist, callback) {
// console.log("createDocs...")
copyDir(src, dist);
// console.log("copyDir finish exec callback")
if (callback) {
callback();
}
}
createDocs("./resource", "./released/resource/", function () {
console.log("资源拷贝成功")
})
\ No newline at end of file
var exec = require('child_process').exec;
var fs = require("fs");
//用这个生成所有的,最好把createModule里的warn去掉,否则子进程的打不到
const skinDataAll = JSON.parse(fs.readFileSync("./resource/skin.json"));
skinDataAll.children.forEach(c => {
const cmd = "node ./scripts/createModule.js " + c.name;
exec(cmd, { encoding: 'utf8' }, (e) => {
console.log("生成模块:" + c.name)
})
});
var fs = require("fs");
function createHtml(url) {
var js = `//yun.duiba.com.cn/db_games/${url}/output.js`;
var template = fs.readFileSync("./index.html").toString();
//写入released
fs.writeFileSync("./released/index.html", template.replace("./debug/output.js", js))
}
module.exports = createHtml
const fs = require("fs");
const warn = require("./warn");
//类型对应
const DISRES = {
'container': "Container",
'text': "TextField",
'button': "Button",
'sprite': "Sprite",
'rect': "Graphics",
// 'skin'
}
const skinDataAll = JSON.parse(fs.readFileSync("./resource/skin.json"))
//取指令后的参数
let arg = process.argv.splice(2);
//类名
var className = arg[0];
//皮肤名字
var skinName = arg[0]; //arg[1];
//是否弹框,存在参数就是场景
var moduleType = className.indexOf("Scene") > -1 ? "Scene" : "Panel";
// console.log('类名:',className)
// console.log('皮肤名字:',skinName)
var skinData = getSkinDataByName(skinName, skinDataAll);
if (!skinData) {
console.log(skinName + "皮肤不存在");
return
}
var groupName = skinData.name;
var endPath = moduleType == "Panel" ? "./src/panels/" : "./src/scenes/";
// var template =
// (moduleType == "Panel" ?
// 'import { Panel } from "../../module/views/Panel";\n' :
// 'import { Scene } from "../../module/views/Scene";\n') +
// 'export class ' + className + ' extends ' + moduleType + ' {\n' +
// '\tget groupNames() { return ["' + groupName + '"] }\n' +
// '\tget skinName() { return "' + skinName + '" }\n' +
// '\t' + getIds(skinData) + "\n" +
// '\tinitUi() {\n' +
// ' \n' +
// '\t}\n' +
// '\tstart(data) {\n' +
// '\t\tsuper.start();\n' +
// '\t}\n' +
// '\tinitEvents() {\n' +
// '\t\tsuper.initEvents();' +
// ' \n' +
// '\t}\n' +
// '\tremoveEvents() {\n' +
// '\t\tsuper.removeEvents();' +
// ' \n' +
// '\t}\n' +
// '}\n'
var template =
(moduleType == "Panel" ?
'import { Panel } from "../../module/views/Panel";\n' :
'import { Scene } from "../../module/views/Scene";\n') +
`export class ${className} extends ${moduleType} {
get groupNames() { return ["${groupName}"] };
get skinName() { return "${skinName}" };
${getIds(skinData)}
initUi() {
}
start(data) {
super.start();
}
initEvents() {
super.initEvents();
}
removeEvents() {
super.removeEvents();
}
}\n\n`
//取出skinName里的Item
var skins = getItemSkins(skinData)
if (skins.length) template = 'import { Item } from "../../module/views/Item";\n' + template;
for (var i = 0; i < skins.length; i++) {
var skin = skins[i];
// template +=
// 'class ' + upperCaseFirstChar(skin.name) + ' extends Item {\n' +
// '\tget skinName() { return "' + skin.name + '" }\n' +
// '\t' + getIds(skin) + "\n" +
// '\tinitUi(data?) {\n' +
// ' \n' +
// '\t}\n' +
// '\tupdateData(data?) {\n' +
// ' \n' +
// '\t}\n' +
// '\tinitData(id: number, data: any): void {\n' +
// '\t\tsuper.initData(id,data);\n' +
// ' \n' +
// '\t}\n' +
// '\tresetData() {\n' +
// ' \n' +
// '\t}\n' +
// '}\n'
template +=
`class ${upperCaseFirstChar(skin.name)} extends Item {
get skinName() { return "${skin.name}" }
${getIds(skin)}
initUi(data?) {
}
updateData(data?) {
}
initData(id: number, data: any): void {
if (id < 0 || !data) return;
super.initData(id,data);
}
resetData() {
}
}\n\n`;
}
//不存在时建一个
if (!fs.existsSync(endPath)) fs.mkdirSync(endPath);
//判断ts文件是否已存在
if (fs.existsSync(endPath + className + ".ts")) {
warn(
className + ".ts已存在,是否覆盖",
() => {
fs.writeFileSync(endPath + className + ".ts", template)
},
() => { }
)
} else {
fs.writeFileSync(endPath + className + ".ts", template)
}
// function cutIds(ids) {
// var str = ''
// var arr = ids.split(";")
// // console.log(arr)
// arr.forEach(element => {
// if (element) str += element + ";\n\t"
// });
// return str
// }
/**
* 获取皮肤数据
* @param {*} skinName
* @param {*} skinNode
*/
function getSkinDataByName(skinName, skinNode) {
if (!skinNode || !skinNode.children || !skinNode.children.length) return null;
for (var i = 0; i < skinNode.children.length; i++) {
var child = skinNode.children[i];
//皮肤数据得是容器
if (child.name == skinName && (child.type == "container" || child.type == "item")) return child;
var gson = getSkinDataByName(skinName, child);
if (gson) return gson
}
return null;
}
//取出所有的Item的皮肤,标记为item的
function getItemSkins(skinNode) {
var arr = []
for (var i = 0; i < skinNode.children.length; i++) {
var c = skinNode.children[i];
if (c.type == 'item') arr.push(c);
if (c.children) getItemSkins(c).forEach((cc) => {
arr.push(cc);
})
}
return arr
}
function getIds(skinNode, str) {
str = str || ''
for (var i = 0; i < skinNode.children.length; i++) {
var c = skinNode.children[i];
if (c.id) str += c.id + ": FYGE." + DISRES[c.type] + ";\n\t";
//作为item的不进
if (c.type == "container" && c.type != "item") str = getIds(c, str);
}
return str
}
function upperCaseFirstChar(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
var fs = require("fs");
var iconv = require('iconv-lite');
var del = require('del');
var readPath = "./released/resource/";
//读取json文件
var data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");//GBK
//反序列化
data = JSON.parse(data); //eval(data)
//取出里面的图片,暂存到tm文件夹中,同时删除文件夹里的,和本身json里的
if (!fs.existsSync("./released/tm"))
fs.mkdirSync("./released/tm");
for (var i = 0; i < data.groups.length; i++) {
var name = data.groups[i].name;
var path = readPath + name + "/";
var arr = data.groups[i].keys.split(",");
//取出图片的,注意已排除jpg
var images = arr.filter((f) => { return (f.substr(-4) == ".png" /*|| f.substr(-4) == ".jpg"*/) })
//没有图片,
if (!images.length) continue;
//去掉原先数据里的
// data.groups[i].keys = arr.filter((f) => { return (f.substr(-4) != ".png" && f.substr(-4) != ".jpg") }).join(",");
//添加新的json,加到atlas里
// if (data.groups[i].keys) data.groups[i].keys += ","
data.groups[i].atlas = name + ".json"
//读取原先路径里的图片,写到tm的文件夹里,并删除原文件夹里的图片
fs.mkdirSync("./released/tm/" + name);
for (var m = 0; m < images.length; m++) {
fs.writeFileSync(
"./released/tm/" + name + "/" + images[m],
fs.readFileSync(path + images[m])
)
del(path + images[m])
}
}
//序列化
fs.writeFileSync(readPath + "res.json", JSON.stringify(data, "", "\t"));
const fs = require('fs');
const ts = require("typescript");
const regLine = /(export|declare)((?!from).)*/g;
function compile(fileNames, options) {
const host = ts.createCompilerHost(options);
const exports = [];
host.writeFile = (fileName, fileContent) => {
const result = fileContent.match(regLine);
for (let line of result) {
if (line.match(/export (default)? \w+;/)) {
continue;
}
if (line.endsWith(';')) {
if (!line.startsWith('_') && !line.startsWith('export default function')) {
exports.push(line);
}
} else {
if (line.endsWith('{')) {
let start = fileContent.indexOf(line);
const block = fileContent.substring(start, fileContent.indexOf('\n}', start) + 2);
if (!block.startsWith('_')) {
exports.push(block);
}
}
}
}
};
const program = ts.createProgram(fileNames, options, host);
program.emit();
let allExports = exports.join('\n\n')
.replace(/export default _default;/g, '')
.replace(/export declare/g, 'export ')
.replace(/export default/g, 'export ')
.replace(/declare /g, 'export ');
// const content = `declare module FYGE{${allExports}}`;
// const content = `declare namespace FYGE{${allExports}}\ndeclare module "fyge" {export = FYGE;}`;
const content = `declare namespace output{${allExports}}`;//不作为npm使用时还是去掉吧
fs.writeFileSync('build/output.d.ts', content);
}
compile(process.argv.slice(2), {
allowJs: true,
declaration: true,
emitDeclarationOnly: true,
});
var fs = require("fs");
var del = require('del');
function delDir(path, isSelf) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach((file, index) => {
let curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
delDir(curPath); //递归删除文件夹
} else {
fs.unlinkSync(curPath); //删除文件
}
});
if (!isSelf) fs.rmdirSync(path);
}
}
var paths = './released/';//设置删除路径
// delDir(paths, true);//删除文件夹
del(paths).then(() => {
fs.mkdirSync(paths);
}).catch(()=>{
fs.mkdirSync(paths);
})
// var tasks = [];
// function addTask(task) {
// tasks.push(task);
// }
// function next() {
// if (tasks.length > 0) {
// tasks.shift()();
// } else {
// return;
// }
// }
// var delRel = function () {
// del(paths).then(() => {
// // console.log("del")
// next();
// })
// }
// var createRel = function () {
// fs.mkdirSync(paths);
// // console.log("create")
// next();
// }
// addTask(delRel)
// addTask(createRel)
// next();
\ No newline at end of file
var del = require('del');
del("./released/tm")
\ No newline at end of file
/**
* flushRes.js
* Created by 还有醋v on 2022/9/19 下午6:10.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
//生成res.json
//遍历资源文件夹,生成
const fs = require('fs');
const path = require("path");
function flushRes(pathOrigin = ".") {
const readPath = "./resource/"
const files = fs.readdirSync(readPath);
const obj = { groups: [] };//每项包括keys合name
files.forEach(function (file) {
//路径
let fPath = path.join(readPath, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
//继续读每个子文件夹,json和png名字有相同的,只留json,
let sonFiles = fs.readdirSync(fPath);
//没有文件
if (!sonFiles.length) return;
//取出所有json
const jsons = sonFiles.filter((f) => {
return f.substr(-5) === ".json";
});
//去掉json所带png的图片
sonFiles = sonFiles.filter((f) => {
return jsons.indexOf(f.substring(0, f.length - 4) + ".json") === -1
});
//去掉mac上的缓存文件
sonFiles = sonFiles.filter((f) => {
return f !== '.DS_Store'
});
const group = {
keys: "", name: file,
};
for (let i = 0; i < sonFiles.length; i++) {
if (i !== 0) group.keys += ",";
group.keys += sonFiles[i];
}
obj.groups.push(group);
}
})
obj.path = "./resource/";
const writeStr = JSON.stringify(obj, "", "\t");
//生成json
fs.writeFileSync(readPath + "res.json", writeStr);
//TS也更新
const endPath = './src/';
const endFile = `export const ResJson = ${writeStr.replace(
`"path": "./resource/"`,
`"path": "${pathOrigin}/resource/"`
)}`;
fs.writeFileSync(endPath + "ResJson.ts", endFile);
console.log("资源更新完成");
}
flushRes();
exports.flushRes = flushRes;
/*
* aaaa.js
* Created by 还有醋v on 2022/5/25.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
const polyfillLibrary = require('polyfill-library');
const fs = require("fs");
polyfillLibrary.getPolyfillString({
uaString: 'Mozilla/5.0 (Linux; Android 4.1.0;) Chrome/29.0.3202.84 Mobile',
minify: true,
features: {
'es5': { },
'Number.isNaN': { },
'Number.isFinite': { },
'Number.isInteger': { },
'Number.parseInt': { },
'Number.parseFloat': { },
'Array.from': { },
'Array.isArray': { },
'Array.prototype.map': { },
'Array.prototype.sort': { },
'Array.prototype.reduce': { },
'Array.prototype.indexOf': { },
'Array.prototype.entries': { },
'Array.prototype.filter': { },
'Array.prototype.forEach': { },
'Object.keys': { },
'Object.values': { },
'Object.assign': { },
'Object.entries': { },
'Promise': { },
'Promise.prototype.finally': { },
'Set': { },
'String.prototype.repeat': { },
'String.prototype.matchAll': { },
'String.prototype.replaceAll': { },
'String.prototype.trim': { },
'String.prototype.trimEnd': { },
'String.prototype.trimStart': { },
'Symbol': { },
}
}).then(function(bundleString) {
fs.writeFileSync("polyfill.js", bundleString);
});
const fs = require("fs");
const iconv = require('iconv-lite');
const path = require('path');
const trans = require("./trans");
const md5 = require('md5');
//用于处理带base64图片的lottie文件,取出图片,同名lottie文件夹,写入代码"./src/lotties/"中;
//别再执行,会覆盖
// return
const pathName = "./lotties";
const outPath = "./resource";
//读文件夹
const files = fs.readdirSync(pathName);
//对每个json文件作处理
files.forEach(function (lottiesFileName) {
// console.log(lottiesFileName)
//后缀不是json的,不处理
if (path.extname(lottiesFileName).indexOf(".json") < 0) return;
//用文件名作为类名和资源文件夹名
const cusName = lottiesFileName.substring(0, lottiesFileName.lastIndexOf(".json"));
//读数据
let data = iconv.decode(fs.readFileSync(pathName + "/" + lottiesFileName), "utf-8");//GBK
//反序列化
data = JSON.parse(data);
//存图片
const assets = data.assets;
if (!assets || !assets.length) return;
//删除属性
delete data.assets;
const copyAssets = [];
const imgOutPath = outPath + "/" + cusName;//data.nm
//建文件夹data.nm
if (!fs.existsSync(imgOutPath)) fs.mkdirSync(imgOutPath);
assets.forEach((e) => {
//没有base64数据,可能是嵌套的
if (!e.p) {
copyAssets.push(e);
return
}
let id = e.id;
// let uuid = guid();
// //存图片
const base64 = e.p.replace(/^data:image\/\w+;base64,/, "");//去掉图片base64码前面部分data:image/png;base64
const dataBuffer = /*new Buffer*/Buffer.from(base64, 'base64'); //把base64码转成buffer对象,
//用用到该图片的图层的名字当作图片名,必须是.png结尾,为了图片去重
let name = data.layers.find((l) => l.refId === id);
//没找到图层,
if (!name) {//再往嵌套图层里的找
for (let ii = 0; ii < assets.length; ii++) {
if (!assets[ii].p) {
name = assets[ii].layers.find((l) => l.refId === id);
if (name) break;
}
}
}
//还没找到图层,不处理
if (!name) return
//不用缓存了,直接用md5;
name = md5(base64);
//修改所有的refId
data.layers.forEach((l) => {
l.refId === id && (l.refId = name)
})
//还有嵌套的
assets.forEach((a) => {
if (!a.p) a.layers.forEach((l) => l.refId === id && (l.refId = name));
})
fs.writeFile(imgOutPath + "/" + name + ".png", dataBuffer, () => 0);
});
//如果存在嵌套图层的,assets加回
if (copyAssets.length) data.assets = copyAssets;
//开始删东西
//是否3d
delete data.ddd;
//版本号,版本必须5.6.10,否则可能有问题
delete data.v;
//遍历删除图层东西
for (let i = 0; i < data.layers.length; i++) {
const l = data.layers[i];
//是否3d,后缀,sr,ao,开始时间,混合模式,特效
["ddd", "cl", "sr", "ao", "st", "bm", "ef"].forEach((e) => delete l[e]);
//ks删除
["o", "r", "p", "a", "s"].forEach((e) => {
const d = l.ks[e];
//ix不知道干嘛用,删了
delete d.ix;
//貌似标记0是没有关键帧的,1是有关键帧的
delete d.a;
//删除k里数据,都要用了,不能删,看情况用吧,如果不需要补间的,用Tween拼的,就删掉,不删只是文件大点
// if (d.k.length && typeof d.k[0] == "object") {
// d.k.forEach((ee) => {
// ["i", "o", "ti", "to"/*, "h"*/].forEach((eee) => { delete ee[eee]; })//h需要判断是否是缓动
// })
// }
})
}
//导出代码到src的lotties文件夹,名字就是lottie动画名字,资源名字临时处理了,首页加载动画用图层的nm,bonustime用refid
const endPath = './src/lotties';
if (!fs.existsSync(endPath)) fs.mkdirSync(endPath);
//文件名字修改,中划线变成下划线,中文变拼音
const fileName = trans(cusName/*data.nm*/).replace(/-/g, "_");
//导出对象直接用lottie动画名字
const endFile = `export const ${fileName} = ${JSON.stringify(data, "", "\t")}`;
//文件名字用lottie动画名字
fs.writeFileSync(endPath + "/" + fileName + ".ts", endFile);
console.log("生成文件:" + fileName + ".ts");
});
const fs = require('fs');
const path = require('path');
const Os = require('os');
const { exec } = require('child_process');
/** 压缩引擎路径表 */
const enginePathMap = {
/** macOS */
'darwin': 'pngquant/macos/pngquant',
/** Windows */
'win32': 'pngquant/windows/pngquant'
}
const platform = Os.platform();
const pngquantPath = path.join(__dirname, enginePathMap[platform]);
// 设置引擎文件的执行权限(仅 macOS)
if (pngquantPath && platform === 'darwin') {
if (fs.statSync(pngquantPath).mode != 33261) {
// 默认为 33188
fs.chmodSync(pngquantPath, 33261);
}
}
const qualityParam = `--quality 60-80`;
const speedParam = `--speed 3`;
const skipParam = '--skip-if-larger';
const outputParam = '--ext=.png';
const writeParam = '--force';
const compressOptions = `${qualityParam} ${speedParam} ${skipParam} ${outputParam} ${writeParam}`;
// 要处理的图片文件夹路径
const altasPath = path.join(__dirname, "../released/resource/");
const folders = getFolders(altasPath);
const files = folders.map((folder) => {
return altasPath + folder + '/*.png';
})
console.time("压缩时间:");
// compress([`${altasPath}**/*.png`]); // 这个慢很多,但是可以多层级
// 这个快很多,但是只能一层级
compress(files)
.then(() => {
console.timeEnd("压缩时间:");
});
/**
* 压缩
* @param {string[]} pathArr 文件数组
* @param {object} options 压缩参数
*/
async function compress(pathArr, options = compressOptions) {
const tasks = [];
pathArr.forEach((filePath, i) => {
if (!filePath) {
console.error(i, filePath);
return;
}
// 加入压缩队列
tasks.push(new Promise((resolve) => {
try {
const command = `"${pngquantPath}" ${filePath} ${options}`;
exec(command, (error, stdout, stderr) => {
if(stderr) console.error(stderr);
resolve();
});
} catch (e) {
console.error(e);
resolve();
}
}));
});
await Promise.all(tasks);
}
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function (file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
var fs = require("fs");
var path = require('path');
var del = require('del');
var iconv = require('iconv-lite');
const join = require('path').join;
//写入图集的文件夹,将文件夹内所有的json合并,并删除原先json
var readPath = "./released/resource/";
//读取json文件
var data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");//GBK
//反序列化
data = JSON.parse(data);
var files = fs.readdirSync(readPath);
// let obj = {};
let count = 0;
let countAll = files.length
files.forEach(function (file) {
//路径
let fPath = join(readPath, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
//读文件夹fPath里的json文件
fs.readdir(fPath, function (err, files) {
if (err) {
console.warn(err)
} else {
var hasJson
//遍历
for (var i = 0; i < files.length; i++) {
let filename = files[i];
if (filename.indexOf(".json") == -1) continue
hasJson = true;
//获取当前文件的绝对路径
let filedir = path.join(fPath, filename);
let content = fs.readFileSync(filedir, 'utf-8');
let group = getGroupByName(filename.replace(".json", ""), data.groups)
group.atlas = JSON.parse(content);
//删除原先json
del(filedir)
if (++count == countAll) endFun();
}
if(!hasJson)if (++count == countAll) endFun();
//序列化,不格式化,节省内存
}
})
} else {
if (++count == countAll) endFun();
}
})
function endFun() {
console.log("资源配置js生成完毕")
// del(join(readPath, "res.json"))
fs.writeFileSync(readPath + "res.json", JSON.stringify(data, "", "\t"));
}
function getGroupByName(name, groups) {
var group;
for (var i = 0; i < groups.length; i++) {
if (groups[i].name === name) {
group = groups[i];
break;
}
}
return group
}
pngquant and libimagequant are derived from code by Jef Poskanzer and Greg Roelofs
licensed under pngquant's original licenses (near the end of this file),
and contain extensive changes and additions by Kornel Lesiński
licensed under GPL v3 or later.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant © 2009-2018 by Kornel Lesiński.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The quantization and dithering code in pngquant is lifted from Jef Poskanzer's
'ppmquant', part of his wonderful PBMPLUS tool suite.
Greg Roelofs hacked it into a (in his words) "slightly cheesy" 'pamquant' back
in 1997 (see http://pobox.com/~newt/greg_rgba.html) and finally he ripped out
the cheesy file-I/O parts and replaced them with nice PNG code in December
2000. The PNG reading and writing code is a merged and slightly simplified
version of readpng, readpng2, and writepng from his book "PNG: The Definitive
Guide."
In 2014 Greg has relicensed the code under the simplified BSD license.
Note that both licenses are basically BSD-like; that is, use the code however
you like, as long as you acknowledge its origins.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant.c:
© 1989, 1991 by Jef Poskanzer.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant.c and rwpng.c/h:
© 1997-2002 by Greg Roelofs; based on an idea by Stefan Schneider.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# pngquant 2 [![build](https://travis-ci.org/kornelski/pngquant.svg?branch=master)](https://travis-ci.org/kornelski/pngquant)
[pngquant](https://pngquant.org) is a PNG compressor that significantly reduces file sizes by converting images to a more efficient 8-bit PNG format *with alpha channel* (often 60-80% smaller than 24/32-bit PNG files). Compressed images are fully standards-compliant and are supported by all web browsers and operating systems.
[This](https://github.com/kornelski/pngquant) is the official `pngquant` repository. The compression engine is also available [as an embeddable library](https://github.com/ImageOptim/libimagequant).
## Usage
- batch conversion of multiple files: `pngquant *.png`
- Unix-style stdin/stdout chaining: `… | pngquant - | …`
To further reduce file size, try [optipng](http://optipng.sourceforge.net), [ImageOptim](https://imageoptim.com), or [zopflipng](https://github.com/google/zopfli).
## Features
* High-quality palette generation
- advanced quantization algorithm with support for gamma correction and premultiplied alpha
- unique dithering algorithm that does not add unnecessary noise to the image
* Configurable quality level
- automatically finds required number of colors and can skip images which can't be converted with the desired quality
* Fast, modern code
- based on a portable [libimagequant library](https://github.com/ImageOptim/libimagequant)
- C99 with no workarounds for legacy systems or compilers ([apart from Visual Studio](https://github.com/kornelski/pngquant/tree/msvc))
- multicore support (via OpenMP) and Intel SSE optimizations
## Options
See `pngquant -h` for full list.
### `--quality min-max`
`min` and `max` are numbers in range 0 (worst) to 100 (perfect), similar to JPEG. pngquant will use the least amount of colors required to meet or exceed the `max` quality. If conversion results in quality below the `min` quality the image won't be saved (if outputting to stdin, 24-bit original will be output) and pngquant will exit with status code 99.
pngquant --quality=65-80 image.png
### `--ext new.png`
Set custom extension (suffix) for output filename. By default `-or8.png` or `-fs8.png` is used. If you use `--ext=.png --force` options pngquant will overwrite input files in place (use with caution).
### `-o out.png` or `--output out.png`
Writes converted file to the given path. When this option is used only single input file is allowed.
### `--skip-if-larger`
Don't write converted files if the conversion isn't worth it.
### `--speed N`
Speed/quality trade-off from 1 (slowest, highest quality, smallest files) to 11 (fastest, less consistent quality, light comperssion). The default is 4. It's recommended to keep the default, unless you need to generate images in real time (e.g. map tiles). Higher speeds are fine with 256 colors, but don't handle lower number of colors well.
### `--nofs`
Disables Floyd-Steinberg dithering.
### `--floyd=0.5`
Controls level of dithering (0 = none, 1 = full). Note that the `=` character is required.
### `--posterize bits`
Reduce precision of the palette by number of bits. Use when the image will be displayed on low-depth screens (e.g. 16-bit displays or compressed textures in ARGB444 format).
### `--strip`
Don't copy optional PNG chunks. Metadata is always removed on Mac (when using Cocoa reader).
See [man page](https://github.com/kornelski/pngquant/blob/master/pngquant.1) (`man pngquant`) for the full list of options.
## License
pngquant is dual-licensed:
* Under **GPL v3** or later with an additional [copyright notice](https://github.com/kornelski/pngquant/blob/master/COPYRIGHT) that must be kept for the older parts of the code.
* Or [a **commercial license**](https://supso.org/projects/pngquant) for use in non-GPL software (e.g. closed-source or App Store distribution). You can [get the license via Super Source](https://supso.org/projects/pngquant). Email kornel@pngquant.org if you have any questions.
pngquant and libimagequant are derived from code by Jef Poskanzer and Greg Roelofs
licensed under pngquant's original licenses (near the end of this file),
and contain extensive changes and additions by Kornel Lesiński
licensed under GPL v3 or later.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant © 2009-2018 by Kornel Lesiński.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The quantization and dithering code in pngquant is lifted from Jef Poskanzer's
'ppmquant', part of his wonderful PBMPLUS tool suite.
Greg Roelofs hacked it into a (in his words) "slightly cheesy" 'pamquant' back
in 1997 (see http://pobox.com/~newt/greg_rgba.html) and finally he ripped out
the cheesy file-I/O parts and replaced them with nice PNG code in December
2000. The PNG reading and writing code is a merged and slightly simplified
version of readpng, readpng2, and writepng from his book "PNG: The Definitive
Guide."
In 2014 Greg has relicensed the code under the simplified BSD license.
Note that both licenses are basically BSD-like; that is, use the code however
you like, as long as you acknowledge its origins.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant.c:
© 1989, 1991 by Jef Poskanzer.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pngquant.c and rwpng.c/h:
© 1997-2002 by Greg Roelofs; based on an idea by Stefan Schneider.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@echo off
set path=%~d0%~p0
:start
"%path%pngquant.exe" --force --verbose --quality=45-85 %1
"%path%pngquant.exe" --force --verbose --ordered --speed=1 --quality=50-90 %1
shift
if NOT x%1==x goto start
@echo off
set path=%~d0%~p0
:start
"%path%pngquant.exe" --force --verbose 256 %1
shift
if NOT x%1==x goto start
# pngquant 2
[pngquant](https://pngquant.org) is a PNG compresor that significantly reduces file sizes by converting images to a more efficient 8-bit PNG format *with alpha channel* (often 60-80% smaller than 24/32-bit PNG files). Compressed images are fully standards-compliant and are supported by all web browsers and operating systems.
[This](https://github.com/kornelski/pngquant) is the official `pngquant` repository. The compression engine is also available [as an embeddable library](https://github.com/ImageOptim/libimagequant).
## Usage
- batch conversion of multiple files: `pngquant *.png`
- Unix-style stdin/stdout chaining: `… | pngquant - | …`
To further reduce file size, try [optipng](http://optipng.sourceforge.net), [ImageOptim](https://imageoptim.com), or [zopflipng](https://github.com/google/zopfli).
## Features
* High-quality palette generation
- advanced quantization algorithm with support for gamma correction and premultiplied alpha
- unique dithering algorithm that does not add unnecessary noise to the image
* Configurable quality level
- automatically finds required number of colors and can skip images which can't be converted with the desired quality
* Fast, modern code
- based on a portable [libimagequant library](https://github.com/ImageOptim/libimagequant)
- C99 with no workarounds for legacy systems or compilers ([apart from Visual Studio](https://github.com/kornelski/pngquant/tree/msvc))
- multicore support (via OpenMP) and Intel SSE optimizations
## Options
See `pngquant -h` for full list.
### `--quality min-max`
`min` and `max` are numbers in range 0 (worst) to 100 (perfect), similar to JPEG. pngquant will use the least amount of colors required to meet or exceed the `max` quality. If conversion results in quality below the `min` quality the image won't be saved (if outputting to stdin, 24-bit original will be output) and pngquant will exit with status code 99.
pngquant --quality=65-80 image.png
### `--ext new.png`
Set custom extension (suffix) for output filename. By default `-or8.png` or `-fs8.png` is used. If you use `--ext=.png --force` options pngquant will overwrite input files in place (use with caution).
### `-o out.png` or `--output out.png`
Writes converted file to the given path. When this option is used only single input file is allowed.
### `--skip-if-larger`
Don't write converted files if the conversion isn't worth it.
### `--speed N`
Speed/quality trade-off from 1 (slowest, highest quality, smallest files) to 11 (fastest, less consistent quality, light comperssion). The default is 3. It's recommended to keep the default, unless you need to generate images in real time (e.g. map tiles). Higher speeds are fine with 256 colors, but don't handle lower number of colors well.
### `--nofs`
Disables Floyd-Steinberg dithering.
### `--floyd=0.5`
Controls level of dithering (0 = none, 1 = full). Note that the `=` character is required.
### `--posterize bits`
Reduce precision of the palette by number of bits. Use when the image will be displayed on low-depth screens (e.g. 16-bit displays or compressed textures in ARGB444 format).
### `--strip`
Don't copy optional PNG chunks. Metadata is always removed on Mac (when using Cocoa reader).
See [man page](https://github.com/kornelski/pngquant/blob/master/pngquant.1) (`man pngquant`) for the full list of options.
## License
pngquant is dual-licensed:
* Under **GPL v3** or later with an additional [copyright notice](https://github.com/kornelski/pngquant/blob/master/COPYRIGHT) that must be kept for the older parts of the code.
* Or [a **commercial license**](https://supportedsource.org/projects/pngquant) for use in non-GPL software (e.g. closed-source or App Store distribution). You can [get the license via Supported Source](https://supportedsource.org/projects/pngquant/purchase). Email kornel@pngquant.org if you have any questions.
var fs = require("fs");
var PSD = require('psd');
var path = require('path');
// const mkdirp = require('mkdirp');
//千万别再执行,否则覆盖
// return
var options = {
//导出图片的目录,没有就导在psd所在目录
outImgDir: "./resource/",
//导出Json的目录,没有就不导出
outJsonDir: "./resource/",
}
//psd文件所在文件夹目录
var pathName = "./psd";
var files = fs.readdirSync(pathName);
//只输出一个数据,就算多个psd,也按照每个psd的第一级进入root的children
var rootStructure = {
'x': 0,
'y': 0,
'type': "container",
'children': []
}
files.forEach(async function (psdFileName) {
//获取当前文件的后缀名
var extname = path.extname(psdFileName);
//后缀psd的,进行切图
if (extname.indexOf(".psd") >= 0) {
const psdFile = pathName + "/" + psdFileName
const psdFilePath = path.resolve(psdFile);
var pathInfo = path.parse(psdFile);
const psdData = PSD.fromFile(psdFilePath);//open(异步),fromDroppedFile(异步,拖入文件),fromFile
psdData.parse();
const rootNode = psdData.tree();
//按照第一层的进行分组导出
for (let i = 0; i < rootNode._children.length; i++) {
//一个组,比如开始页面,游戏页面等
const group111 = rootNode._children[i]
const queueNodes = [];
const queueNodesIndex = [];
const queueNodesName = [];
const queueNodesStructure = [];
//如果不是组,直接导common文件夹
if (!group111._children || !group111._children.length) {
saveAsPng("common", group111.name, group111)
} else {
const groupName = rootNode._children[i].name;
//颠倒一下
group111._children.reverse()
queueNodes.push(group111._children);
queueNodesIndex.push(0);
queueNodesName.push(undefined);
//首层的容器默认都是0,0,所以他的left和top修改下
group111.left = group111.top = 0;
const psdStructure = {
// 'ids': "",
"name": groupName,
'x': 0,
'y': 0,
'type': "container",
'children': []
};
queueNodesStructure.push(psdStructure);
queueLoop: while (0 < queueNodes.length) {
const queueIndex = queueNodes.length - 1;
const nodes = queueNodes[queueIndex];
const nodesStructure = queueNodesStructure[queueIndex];
let nodesIndex = queueNodesIndex[queueIndex];
let nodesName = queueNodesName[queueIndex];
if (nodesName === undefined) {
nodesName = '';
} else {
nodesName += path.sep;
}
while (nodesIndex < nodes.length) {
const node = nodes[nodesIndex];
nodesIndex++;
// if (node.layer.visible === false) continue;
//分割一下
const splitArr = node.name.split("_");
if (node.type === 'group') {
//如果是按钮的组,就单纯按钮的三种贴图,第一个是正常,第二个是无法点击,第三个down
if (splitArr[1] == "btn") {
const structure = {
'name': splitArr[0],
'x': node.left - (node.parent ? node.parent.left : 0),
'y': node.top - (node.parent ? node.parent.top : 0),
'type': "button",
};
structure.props = {}
// structure.source = splitArr[0] + ".png"
if (splitArr[2]) {
structure.id = splitArr[2];
// psdStructure.ids += splitArr[2] + ":FYGE.Button;"
}
saveAsPng(groupName, node._children[0].name, node._children[0]);
structure.props.tUp = node._children[0].name + ".png";
if (node._children[1]) {
saveAsPng(groupName, node._children[1].name, node._children[1]);
structure.props.tDisable = node._children[1].name + ".png";
}
if (node._children[2]) {
saveAsPng(groupName, node._children[2].name, node._children[2]);
structure.props.tDown = node._children[2].name + ".png";
}
nodesStructure.children.push(structure);
}
//单纯的组
else {
//颠倒一下
node._children.reverse()
queueNodes.push(node._children);
queueNodesIndex[queueIndex] = nodesIndex;
queueNodesIndex.push(0);
queueNodesName.push(nodesName + node.name);
const structure = {
'name': splitArr[0],
'x': node.left - (node.parent ? node.parent.left : 0),
'y': node.top - (node.parent ? node.parent.top : 0),
// 'id': splitArr[2]||,//对于group
'type': "container",
'children': [],
};
if (splitArr[1] == "skin" || splitArr[1] == "item") {//这种情况不该有id
structure.type = "item"
} else if (splitArr[1]) {
structure.id = splitArr[1];
// psdStructure.ids += splitArr[1] + ":FYGE.Container;"
}
nodesStructure.children.push(structure);
queueNodesStructure.push(structure);
continue queueLoop;
}
} else {
//如果单纯作为贴图,只保存,不进入节点
if (splitArr[1] == "tex") {
saveAsPng(groupName, splitArr[0], node)
continue;
}
const structure = {
'name': splitArr[0],
'x': node/*.layer*/.left - (node.parent ? node.parent.left : 0),
'y': node/*.layer*/.top - (node.parent ? node.parent.top : 0),
// 'width': node.layer.width,
// 'height': node.layer.height
// 'alpha': node.layer.opacity / 255,
};
//只有不为1才记录alpha
if (node.layer.opacity < 255) structure.alpha = node.layer.opacity / 255;
//如果是文本
if (node.layer.typeTool) {
structure.type = "text";
const text = node.layer.typeTool();
const sizes = text.sizes();
// if (splitArr[0] == "20%") console.log(sizes)
// var size = sizes && sizes.length > 1 ? sizes[0] || 12 :
// sizes ? (sizes[0] || 24) / 2 : 12
var size = (() => {
if (!sizes || !sizes[0]) return 12;
return sizes[0] * text.transform.yy;
})();
// var size = sizes ? sizes[0] || 12 : 12 //这个psd又是正常的
const colors = text.colors()[0];
structure.props = {
text: text.textValue.replace("\r", "\n"),
size,
fillColor: rgb2String(colors),
textAlpha: colors[3] / 255 || 1,
}
if (splitArr[1]) {
//加入全局,方便复制
// psdStructure.ids += splitArr[1] + ":FYGE.TextField;";
structure.id = splitArr[1];
}
}
//如果是矢量图,考虑是否需要,简单点判断吧
else if (node.layer.solidColor &&
node.layer.vectorMask().paths[2].numPoints == 4 &&
(!node.layer.vectorMask().paths[3] || node.layer.vectorMask().paths[3].recordType == 2)
) {
const { r, g, b } = node.layer.solidColor();
let fillColor = rgb2String([r, g, b]);
structure.type = 'rect';
structure.props = {
width: node.width,
height: node.height,
fillColor
}
if (splitArr[1]) {
structure.id = splitArr[1];
// psdStructure.ids += splitArr[1] + ":FYGE.Graphics;"
}
}
//标记过按钮的
else if (splitArr[1] == "btn") {
structure.type = "button";
structure.props = {
tUp: splitArr[0] + ".png"
}
// structure.source = splitArr[0] + ".png"
if (splitArr[2]) {
structure.id = splitArr[2];
// psdStructure.ids += splitArr[2] + ":FYGE.Button;"
}
saveAsPng(groupName, splitArr[0], node)
}
//保存图片
else {
structure.type = "sprite";
//如果标记过jpg的
if (splitArr[1] == "jpg") {
structure.props = {
source: splitArr[0] + ".jpg"
}
// structure.source = splitArr[0] + ".jpg"
saveAsPng(groupName, splitArr[0], node, "jpg");
if (splitArr[2]) {
structure.id = splitArr[2];
// psdStructure.ids += splitArr[2] + ":FYGE.Sprite;"
}
} else {
structure.props = {
source: splitArr[0] + ".png"
}
// structure.source = splitArr[0] + ".png"
saveAsPng(groupName, splitArr[0], node);
if (splitArr[1]) {
structure.id = splitArr[1];
// psdStructure.ids += splitArr[1] + ":FYGE.Sprite;"
}
}
}
nodesStructure.children.push(structure);
}
}
queueNodes.pop();
queueNodesIndex.pop();
queueNodesName.pop();
queueNodesStructure.pop();
}
//存入root
rootStructure.children.push(psdStructure)
// const outJsonData = JSON.stringify(psdStructure/*.group*/, "", "\t");
//如果需要导出ui数据
// if (options.outJsonDir) {
// const outJsonDirPath = path.resolve(options.outJsonDir + groupName);
// const outJsonPath = path.join(outJsonDirPath, groupName + '.json');
// // make output directory.
// if (!fs.existsSync(outJsonDirPath)) {
// fs.mkdirSync(outJsonDirPath);
// }
// // output file.
// fs.writeFileSync(outJsonPath, outJsonData);
// }
}
}
}
})
//导出所有的数据
if (options.outJsonDir) {
//倒转一下所有children的层级
const outJsonData = JSON.stringify(rootStructure/*.group*/, "", "\t");
const outJsonDirPath = path.resolve(options.outJsonDir);
const outJsonPath = path.join(outJsonDirPath, 'skin.json');
if (!fs.existsSync(outJsonDirPath)) {
fs.mkdirSync(outJsonDirPath);
}
fs.writeFileSync(outJsonPath, outJsonData);
//代码也保存
var endPath = './src/';
var endFile = `export const SkinJson = ${outJsonData}`
fs.writeFileSync(endPath + "SkinJson.ts", endFile);
}
function rgb2String(rgb) {
var hex = ((rgb[0] << 16) + (rgb[1] << 8) + (rgb[2] | 0));
hex = hex.toString(16);
hex = '000000'.substr(0, 6 - hex.length) + hex;
return `#${hex}`;
}
/**
*
* @param {string} dirName 文件夹名字
* @param {string} name 图片名称
* @param {*} node
* @param {*} format 保存图片格式,默认png
*/
function saveAsPng(dirName, name, node, format = "png") {
const outImgDirPath = options.outImgDir + dirName;
// mkdirp.sync(outImgDirPath);
if (!fs.existsSync(outImgDirPath)) fs.mkdirSync(outImgDirPath);
console.log('保存图片:' + name + '.' + format);
//保存成图片
node.layer.image.saveAsPng(path.join(outImgDirPath, name + '.' + format));
}
var fs = require("fs");
var PSD = require('psd');
var path = require('path');
// const mkdirp = require('mkdirp');
//千万别再执行,否则覆盖
// return
//取指令后的参数
let arg = process.argv.splice(2);
//psd文件名字
var psdName = arg[0];
var options = {
//导出图片的目录,没有就导在psd所在目录,单视图处理都先进psd,
outImgDir: "./psd/",
//导出Json的目录,没有就不导出,单视图处理都先进psd,剩下的自己复制,为了不影响原皮肤数据
outJsonDir: "./psd/",
}
//psd文件所在文件夹目录
var pathName = "./psd";
//只输出一个数据,就算多个psd,也按照每个psd的第一级进入root的children
var rootStructure = {
'x': 0,
'y': 0,
'type': "container",
'children': []
}
const psdFile = pathName + "/" + psdName + ".psd";
const psdFilePath = path.resolve(psdFile);
// var pathInfo = path.parse(psdFile);
const psdData = PSD.fromFile(psdFilePath);//open(异步),fromDroppedFile(异步,拖入文件),fromFile
psdData.parse();
const rootNode = psdData.tree();
//按照第一层的进行分组导出
for (let i = 0; i < rootNode._children.length; i++) {
//一个组,比如开始页面,游戏页面等
const group111 = rootNode._children[i]
const queueNodes = [];
const queueNodesIndex = [];
const queueNodesName = [];
const queueNodesStructure = [];
//如果不是组,直接导common文件夹
if (!group111._children || !group111._children.length) {
saveAsPng("common", group111.name, group111)
} else {
const groupName = rootNode._children[i].name;
//颠倒一下
group111._children.reverse()
queueNodes.push(group111._children);
queueNodesIndex.push(0);
queueNodesName.push(undefined);
//首层的容器默认都是0,0,所以他的left和top修改下
group111.left = group111.top = 0;
const psdStructure = {
// 'ids': "",
"name": groupName,
'x': 0,
'y': 0,
'type': "container",
'children': []
};
queueNodesStructure.push(psdStructure);
queueLoop: while (0 < queueNodes.length) {
const queueIndex = queueNodes.length - 1;
const nodes = queueNodes[queueIndex];
const nodesStructure = queueNodesStructure[queueIndex];
let nodesIndex = queueNodesIndex[queueIndex];
let nodesName = queueNodesName[queueIndex];
if (nodesName === undefined) {
nodesName = '';
} else {
nodesName += path.sep;
}
while (nodesIndex < nodes.length) {
const node = nodes[nodesIndex];
nodesIndex++;
// if (node.layer.visible === false) continue;
//分割一下
const splitArr = node.name.split("_");
if (node.type === 'group') {
//如果是按钮的组,就单纯按钮的三种贴图,第一个是正常,第二个是无法点击,第三个down
if (splitArr[1] == "btn") {
const structure = {
'name': splitArr[0],
'x': node.left - (node.parent ? node.parent.left : 0),
'y': node.top - (node.parent ? node.parent.top : 0),
'type': "button",
};
structure.props = {}
// structure.source = splitArr[0] + ".png"
if (splitArr[2]) {
structure.id = splitArr[2];
// psdStructure.ids += splitArr[2] + ":FYGE.Button;"
}
saveAsPng(groupName, node._children[0].name, node._children[0]);
structure.props.tUp = node._children[0].name + ".png";
if (node._children[1]) {
saveAsPng(groupName, node._children[1].name, node._children[1]);
structure.props.tDisable = node._children[1].name + ".png";
}
if (node._children[2]) {
saveAsPng(groupName, node._children[2].name, node._children[2]);
structure.props.tDown = node._children[2].name + ".png";
}
nodesStructure.children.push(structure);
}
//单纯的组
else {
//颠倒一下
node._children.reverse()
queueNodes.push(node._children);
queueNodesIndex[queueIndex] = nodesIndex;
queueNodesIndex.push(0);
queueNodesName.push(nodesName + node.name);
const structure = {
'name': splitArr[0],
'x': node.left - (node.parent ? node.parent.left : 0),
'y': node.top - (node.parent ? node.parent.top : 0),
// 'id': splitArr[2]||,//对于group
'type': "container",
'children': [],
};
if (splitArr[1] == "skin" || splitArr[1] == "item") {//这种情况不该有id,但是貌似没法集合id了
structure.type = "item"
} else if (splitArr[1]) {
structure.id = splitArr[1];
// psdStructure.ids += splitArr[1] + ":FYGE.Container;"
}
nodesStructure.children.push(structure);
queueNodesStructure.push(structure);
continue queueLoop;
}
} else {
//如果单纯作为贴图,只保存,不进入节点
if (splitArr[1] == "tex") {
saveAsPng(groupName, splitArr[0], node)
continue;
}
const structure = {
'name': splitArr[0],
'x': node/*.layer*/.left - (node.parent ? node.parent.left : 0),
'y': node/*.layer*/.top - (node.parent ? node.parent.top : 0),
// 'width': node.layer.width,
// 'height': node.layer.height
// 'alpha': node.layer.opacity / 255,
};
//只有不为1才记录alpha
if (node.layer.opacity < 255) structure.alpha = node.layer.opacity / 255;
//如果是文本
if (node.layer.typeTool) {
structure.type = "text";
const text = node.layer.typeTool();
const sizes = text.sizes();
// if (splitArr[0] == "20%") console.log(sizes)
// var size = sizes && sizes.length > 1 ? sizes[0] || 12 :
// sizes ? (sizes[0] || 24) / 2 : 12
var size = (() => {
if (!sizes || !sizes[0]) return 12;
return sizes[0] * text.transform.yy;
})();
// var size = sizes ? sizes[0] || 12 : 12 //这个psd又是正常的
const colors = text.colors()[0];
structure.props = {
text: text.textValue.replace("\r", "\n"),
size,
fillColor: rgb2String(colors),
textAlpha: colors[3] / 255 || 1,
}
if (splitArr[1]) {
//加入全局,方便复制
// psdStructure.ids += splitArr[1] + ":FYGE.TextField;";
structure.id = splitArr[1];
}
}
//如果是矢量图,考虑是否需要,简单点判断吧
else if (node.layer.solidColor &&
node.layer.vectorMask().paths[2].numPoints == 4 &&
(!node.layer.vectorMask().paths[3] || node.layer.vectorMask().paths[3].recordType == 2)
) {
const { r, g, b } = node.layer.solidColor();
let fillColor = rgb2String([r, g, b]);
structure.type = 'rect';
structure.props = {
width: node.width,
height: node.height,
fillColor
}
if (splitArr[1]) {
structure.id = splitArr[1];
// psdStructure.ids += splitArr[1] + ":FYGE.Graphics;"
}
}
//标记过按钮的
else if (splitArr[1] == "btn") {
structure.type = "button";
structure.props = {
tUp: splitArr[0] + ".png"
}
// structure.source = splitArr[0] + ".png"
if (splitArr[2]) {
structure.id = splitArr[2];
// psdStructure.ids += splitArr[2] + ":FYGE.Button;"
}
saveAsPng(groupName, splitArr[0], node)
}
//保存图片
else {
structure.type = "sprite";
//如果标记过jpg的
if (splitArr[1] == "jpg") {
structure.props = {
source: splitArr[0] + ".jpg"
}
// structure.source = splitArr[0] + ".jpg"
saveAsPng(groupName, splitArr[0], node, "jpg");
if (splitArr[2]) {
structure.id = splitArr[2];
// psdStructure.ids += splitArr[2] + ":FYGE.Sprite;"
}
} else {
structure.props = {
source: splitArr[0] + ".png"
}
// structure.source = splitArr[0] + ".png"
saveAsPng(groupName, splitArr[0], node);
if (splitArr[1]) {
structure.id = splitArr[1];
// psdStructure.ids += splitArr[1] + ":FYGE.Sprite;"
}
}
}
nodesStructure.children.push(structure);
}
}
queueNodes.pop();
queueNodesIndex.pop();
queueNodesName.pop();
queueNodesStructure.pop();
}
//存入root
rootStructure.children.push(psdStructure)
// const outJsonData = JSON.stringify(psdStructure/*.group*/, "", "\t");
//如果需要导出ui数据
// if (options.outJsonDir) {
// const outJsonDirPath = path.resolve(options.outJsonDir + groupName);
// const outJsonPath = path.join(outJsonDirPath, groupName + '.json');
// // make output directory.
// if (!fs.existsSync(outJsonDirPath)) {
// fs.mkdirSync(outJsonDirPath);
// }
// // output file.
// fs.writeFileSync(outJsonPath, outJsonData);
// }
}
}
//导出所有的数据
if (options.outJsonDir) {
//倒转一下所有children的层级
const outJsonData = JSON.stringify(rootStructure/*.group*/, "", "\t");
const outJsonDirPath = path.resolve(options.outJsonDir);
const outJsonPath = path.join(outJsonDirPath, 'skin.json');
if (!fs.existsSync(outJsonDirPath)) {
fs.mkdirSync(outJsonDirPath);
}
fs.writeFileSync(outJsonPath, outJsonData);
//代码也保存
// var endPath = './src/';
// var endFile = `export const SkinJson = ${outJsonData}`
// fs.writeFileSync(endPath + "SkinJson.ts", endFile);
}
function rgb2String(rgb) {
var hex = ((rgb[0] << 16) + (rgb[1] << 8) + (rgb[2] | 0));
hex = hex.toString(16);
hex = '000000'.substr(0, 6 - hex.length) + hex;
return `#${hex}`;
}
/**
*
* @param {string} dirName 文件夹名字
* @param {string} name 图片名称
* @param {*} node
* @param {*} format 保存图片格式,默认png
*/
function saveAsPng(dirName, name, node, format = "png") {
const outImgDirPath = options.outImgDir + dirName;
// mkdirp.sync(outImgDirPath);
if (!fs.existsSync(outImgDirPath)) fs.mkdirSync(outImgDirPath);
console.log('保存图片:' + name + '.' + format);
//保存成图片
node.layer.image.saveAsPng(path.join(outImgDirPath, name + '.' + format));
}
const path = require("path");
const fs = require("fs");
const exec = require('child_process').exec;
const iconv = require('iconv-lite');
const del = require('del');
const join = require('path').join;
const { packTextures } = require("texture-packer-hycv");
//写入图集的文件夹
const outPath = path.resolve("./released/resource/") + "/";
//读取散图的文件夹
const readPath = path.resolve("./released/tm/");
const files = fs.readdirSync(readPath);
files.forEach(function (file) {
//路径
let fPath = join(readPath, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
//判断文件夹内是否有图片
if (!judgeHasImage(fPath)) return;
//如果文件夹不存在
if (!fs.existsSync(outPath + file)) {
fs.mkdirSync(outPath + file);
} else {
//图集文件存在就删除
if (fs.existsSync(outPath + file + "/" + file + ".json")) {
del(outPath + file + "/" + file + ".json")
}
if (fs.existsSync(outPath + file + "/" + file + ".png")) {
del(outPath + file + "/" + file + ".png")
}
}
packTextures(fPath, outPath + file + "/" + file, 4096, 4096, false, 2, 2, true, true)
//全局命令装过,就直接用命令行
// exec(
// 'packTextures' + //基础指令
// ' -i ' + fPath + //要合图集的文件夹路径
// ' -o ' + outPath + file + "/" + file + //输出路径及名字
// ' --mw ' + 4096 + //最大宽度
// ' --mh ' + 4096 +//最大高度
// ' -p ' + false + //长宽是否2的指数,canvas下没必要,false
// ' --sp ' + 2 + //图片间隔
// ' --bp ' + 2 + //边界间隔
// ' -r ' + true + //是否允许图片旋转
// ' -t ' + true //是否允许裁切图片边缘透明像素
// , { encoding: 'utf8' }, (e) => {
// if (e) {
// console.log(e)
// return
// }
// console.log("生成图集:" + file)
// }
// )
}
})
/**
* 判断文件夹内是否有图片
* @param {*} path
*/
function judgeHasImage(path) {
const files = fs.readdirSync(path);
for (let i = 0; i < files.length; i++) {
const itm = files[i];
const stat = fs.statSync(path + "/" + itm);
if (stat.isDirectory()) {
//递归读取文件
if (judgeHasImage(path + "/" + itm + "/")) return true;
} else {
if (itm.substr(-4) == ".jpg" || itm.substr(-4) == ".png") return true;
}
}
return false;
}
const FormData = require('form-data');
const fs = require("fs");
const tinifyUrl = 'https://tinify.duiba.com.cn/tinify';
function isPng(buffer) {
if (!buffer || buffer.length < 8) {
return false;
}
return buffer[0] === 0x89
&& buffer[1] === 0x50
&& buffer[2] === 0x4E
&& buffer[3] === 0x47
&& buffer[4] === 0x0D
&& buffer[5] === 0x0A
&& buffer[6] === 0x1A
&& buffer[7] === 0x0A;
}
function isJpg(buffer) {
if (!buffer || buffer.length < 3) {
return false;
}
return buffer[0] === 255
&& buffer[1] === 216
&& buffer[2] === 255;
}
/**
* 压缩图片
* @param {Buffer|string} bufferOrFile
* @return Promise<Buffer>
*/
async function tinyImage(bufferOrFile) {
let buffer = bufferOrFile;
if (typeof bufferOrFile === 'string') {
buffer = fs.readFileSync(bufferOrFile);
}
return new Promise((resolve, reject) => {
if (buffer && buffer.length > 0) {
let extname = isPng(buffer) ? 'png' : 'jpeg';
let form = new FormData();
form.append('file', buffer, {
filename: 'image.' + extname,
contentType: 'image/' + extname,
});
form.submit(tinifyUrl, function (err, res) {
if (err) {
reject(err);
}
else {
res.resume();
let resBuffer = Buffer.alloc(0);
res.on('data', (d) => {
resBuffer = Buffer.concat([resBuffer, d], resBuffer.length + d.length);
});
res.on('end', () => {
if (resBuffer.length > 256 || isPng(resBuffer) || isJpg(resBuffer)) {
resolve(resBuffer);
}
else {
let str = resBuffer.toString();
let json;
try {
json = JSON.parse(str);
}
catch (e) {
console.log(e);
}
reject(json.msg);
}
});
res.on('abort', () => {
reject('abort');
});
}
});
}
else {
reject('empty buffer');
}
});
}
module.exports = tinyImage;
This source diff could not be displayed because it is too large. You can view the blob instead.
const fs = require('fs');
const path = require('path');
const co = require('co');
const OSS = require('ali-oss');
const chalk = require('chalk');
const ProgressBar = require('progress');
const iconv = require('iconv-lite');
const config = require("../project.json");
class TuiaAutoUpload {
constructor(props, type) {
this.type = type;
const defaultOptions = {
dir: undefined,
originDir: undefined
}
this.options = Object.assign({}, defaultOptions, props);
if (!this.options.dir || !this.options.originDir) {
console.log(chalk.red('缺少参数,初始化失败'))
return;
}
this.init();
}
init() {
const _this = this;
this.client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: "LTAI5tPUSSxgkEmKPAfVXUQQ",
accessKeySecret: "6sk3EDd1BYrXlAUoh8maMuN7hOMkh1",
bucket: _this.type === 'prod' ? 'duiba' : 'daily-duiba'
});
this.bar = new ProgressBar(chalk.yellow(` 文件上传中 [:bar] :current/${this.files().length} :percent :elapseds`), {
complete: '●',
incomplete: '○',
width: 20,
total: this.files().length,
callback: () => {
console.log(chalk.green('\n All complete.'));
console.log(chalk.blue(`\n 本次队列文件共${this.files().length}个,已存在文件${this.existFiles}个,上传文件${this.uploadFiles}个,上传失败文件${this.errorFiles}个\n`));
}
})
return this;
}
files() {
const _this = this;
if (this._files) return this._files;
this._files = [];
/**
* 文件遍历方法
* @param filePath 需要遍历的文件路径
*/
function fileDisplay(filePath) {
//根据文件路径读取文件,返回文件列表
const files = fs.readdirSync(filePath);
files.forEach(function (filename) {
//获取当前文件的绝对路径
const filedir = path.join(filePath, filename);
//根据文件路径获取文件信息,返回一个fs.Stats对象
const stats = fs.statSync(filedir);
const isFile = stats.isFile();//是文件
const isDir = stats.isDirectory();//是文件夹
if (isFile) {
let sep = '/';
if ('win32' === process.platform)
sep = '\\';
const newDirArr = filedir.split(sep);
newDirArr.shift();
_this._files.push(newDirArr.join('/'));
}
if (isDir) {
fileDisplay(filedir);//递归,如果是文件夹,就继续遍历该文件夹下面的文件
}
});
}
//调用文件遍历方法
fileDisplay(this.options.dir);
return this._files;
}
start() {
this.files().map((file) => {
let _this = this;
const path1 = path.join(path.resolve(__dirname, '..'), 'released', file);
let originFile;
this.existFiles = 0;
this.uploadFiles = 0;
this.errorFiles = 0;
co(function* () {
const originPath = `${_this.options.originDir}${file}`;
try {
originFile = yield _this.client.head(originPath);
} catch (error) {
originFile = error;
}
if (_this.type === 'prod') {
if (originFile.status === 404) {
yield _this.client.put(originPath, path1);
_this.uploadFiles += 1;
} else {
_this.existFiles += 1;
}
} else if (_this.type === 'dev') {
if (originFile.status === 404 || originFile.status === 200) {
_this.existFiles += 1;
}
yield _this.client.put(originPath, path1, {
headers: {
'Cache-Control': 'no-cache'
}
})
_this.uploadFiles += 1;
}
_this.bar.tick();
}).catch(function (err) {
_this.errorFiles += 1;
console.log(err);
});
});
}
}
if (!config.type) {
throw new Error(`project.json 的type不存在.`);
}
if (!config.name) {
throw new Error(`project.json 的name不存在.`);
}
const now = new Date();
const version = Math.round(now.getTime() / 1000);
console.log(chalk.bgMagenta(`资源版本号:\n${version}`));
const autoupload = new TuiaAutoUpload({
dir: './released/',
originDir: `/db_games/${config.type}/${config.name}/${version}/`
}, "prod");
autoupload.start();
const readPath = "./released/resource/";
// 读取json文件
let data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");// GBK
// 反序列化
data = JSON.parse(data);
data.path = `https://yun.duiba.com.cn/db_games/${config.type}/${config.name}/${version}/resource/`;
// 写入目标文件夹,可配置,每个项目必须修改,或者直接和project的保持一致(淘宝项目文件固定后)
const endPath = './src/';
const endFile = `export const ResJson = ${JSON.stringify(data, "", "\t")}`;
fs.writeFileSync(endPath + "ResJson.ts", endFile);
const co = require('co');
const OSS = require('ali-oss');
const config = require("../project.json");
const chalk = require('chalk');
//只打包js时,自执行上传
uploadSingleJs();
function uploadSingleJs(url) {
if (!url) {//不传的时候
if (!config.type) {
throw new Error(`project.json 的type不存在.`)
}
if (!config.name) {
throw new Error(`project.json 的name不存在.`)
}
const now = new Date();
const version = Math.round(now.getTime() / 1000);
url = `${config.type}/${config.name}/${version}`;
require("./createHtml")(`${config.type}/${config.name}/${version}`);
console.log(chalk.bgGreen(`版本号:\n${version}`));
}
const client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: "LTAI5tPUSSxgkEmKPAfVXUQQ",
accessKeySecret: "6sk3EDd1BYrXlAUoh8maMuN7hOMkh1",
bucket: 'duiba'
});
//单js文件上传
co(function* () {
const originPath = `/db_games/${url}/output.js`;
let originFile;
try {
originFile = yield client.head(originPath);
} catch (error) {
originFile = error;
}
if (originFile.status === 404)
yield client.put(originPath, "./released/output.js");
});
//js.map
co(function* () {
const originPath = `/db_games/${url}/map_123_map/output.js.map`;
var originFile;
try {
originFile = yield client.head(originPath);
} catch (error) {
originFile = error;
}
if (originFile.status === 404)
yield client.put(originPath, "./released/output.js.map");
});
}
module.exports = uploadSingleJs
var readline = require('readline');//node上有,不为了锁版本,可以不用安装
/**
* 提醒脚本
* @param {string} msg 提示信息
* @param {Function} resolve yes回调
* @param {Function} reject no回调
*/
function warn(msg, resolve, reject) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(msg + "[y/n]", function (answer) {
switch (answer) {
case 'y':
case 'Y':
case 'yes':
case 'YES':
resolve && resolve();
// 不加close,则不会结束
rl.close();
break;
case 'n':
case 'N':
case 'no':
case 'NO':
default:
reject && reject();
rl.close();
break;
}
});
}
module.exports = warn
/*
* Config.ts
* Created by 还有醋v on 2022/6/2.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
interface IConfig {
dropSpeed?: number, // 掉落速度(px/s)
interval?: number, // 掉落间隔事件(s)
player?: string, // 任务图片
rainObj?: string[], // 掉落物图片
}
const gameConfig: IConfig = {
dropSpeed: 650, // 掉落速度(px/s)
interval: 0.15, // 掉落间隔事件(s)
player: "人物.png", // 任务图片
rainObj: ["金币.png", "红包1.png", "红包2.png", "红包3.png", "fudai.png"], // 掉落物图片
};
export default gameConfig;
export function setConfig(obj: IConfig) {
for (let k in obj) gameConfig[k] = obj[k];
}
import { layers, destroyLayers } from "../module/views/layers";
import { RES } from "../module/RES";
import { changeScene, destroyAllCtrls } from "../module/ctrls";
import { GAME_EVENT, GDispatcher } from "./index";
import { GameScene } from "./scenes/GameScene";
import { ResJson } from "./ResJson";
import { SkinJson } from "./SkinJson";
import { destroyWebNetData } from "./tools/WebNet";
import Tween = FYGE.Tween;
import Stage = FYGE.Stage;
import RENDERER_TYPE = FYGE.RENDERER_TYPE;
import Event = FYGE.Event;
import getEnv = FYGE.getEnv;
import {preloadRes} from "./PreloadRes";
export class Game {
// 主舞台
stage: Stage;
private requestID;
private _pause: boolean;
private canvas: HTMLCanvasElement;
constructor(
canvas: HTMLCanvasElement,
desWidth = 750,
desHeight = 1624,
divWidth?,
divHeight?,
renderType = RENDERER_TYPE.WEBGL,
stageCenter = true,
fixedHeight = false,
resolution?,
) {
let sysInfo;
// 淘宝小程序环境就用canvas初始化
if (!window) { // 自行处理吧,这么判断也不保险,万一淘宝小程序加进了window
FYGE.initedByCanvas(canvas); // 里面会设置env为tb,这个很重要
// @ts-ignore 存在my就初始化
sysInfo = my.getSystemInfoSync();
}
divWidth = divWidth || sysInfo?.windowWidth || document.body.clientWidth;
divHeight = divHeight || sysInfo?.windowHeight || document.body.clientHeight;
resolution = resolution || sysInfo?.pixelRatio || window.devicePixelRatio || 1;
// 建舞台
const stage = this.stage = new Stage(
canvas,
desWidth, // 设计宽度,按设计搞给的就行
desHeight, // 设计高度
divWidth, // 显示宽度,全屏就是屏幕宽度
divHeight, // 显示高度,全屏就是屏幕高度
renderType, // 渲染模式canvas
stageCenter, // 视窗居中裁切
fixedHeight, // 不定高,定宽适配
resolution, // 分辨率
);
this.canvas = canvas; // 赋值下,为了下面的destroy的cancelAnimationFrame
// stage初始化
stage.addEventListener(Event.INIT_STAGE, this.onAddToStage, this);
// 循环
this.loop();
}
private loop = () => {
if (!this._pause) {
Tween.flush();
this.stage.flush();
}
getEnv() == "tb"
// @ts-ignore
? this.requestID = this.canvas.requestAnimationFrame(this.loop)
: this.requestID = window.requestAnimationFrame(this.loop);
}
private async onAddToStage() {
// 初始化层级
layers.init(this.stage);
console.log("初始化层级完成");
// preload common res
await preloadRes('common')
// h5环境时,隐藏加载中
if (getEnv() == "web" && document.getElementById("__loading__")) {
document.getElementById("__loading__").style.display = "none";
}
changeScene(GameScene);
}
initWebEvent() {
const mouseEvent = this.stage.onMouseEvent.bind(this.stage);
this.canvas.addEventListener("touchstart", mouseEvent, false);
this.canvas.addEventListener('touchmove', mouseEvent, false);
this.canvas.addEventListener('touchend', mouseEvent, false);
}
run() {
this._pause = false;
// @ts-ignore Tween计时清零
Tween._lastTime = null;
// 触发onShow
GDispatcher.dispatchEvent({ type: GAME_EVENT.ON_SHOW });
}
/**
* 在小程序隐藏时调用onHide
*/
pause() {
// 触发onHide
GDispatcher.dispatchEvent({ type: GAME_EVENT.ON_HIDE });
}
//在小程序页面卸载时调用onUnload,多次销毁后会有问题,再检查
destroy() {
// Tween都移除,注意吧,可能原先的也被移除,对于多page时注意,会把其他页面的也去掉
Tween.removeAllTweens();
// 停掉计时器
// 为了兼容多page的canvas
FYGE.getEnv() == "tb"
// @ts-ignore
? this.canvas.cancelAnimationFrame(this.requestID)
: window.cancelAnimationFrame(this.requestID);
// 层级销毁
destroyLayers();
// 销毁控制器
destroyAllCtrls();
// 舞台销毁
this.stage.destroy();
// 全局事件置空
GDispatcher.removeAllEventListener();
// 网络数据记录清空
destroyWebNetData();
}
}
import {RES} from "../module/RES";
import {ResJson} from "./ResJson";
import {SkinJson} from "./SkinJson";
export const preloadRes = async (resGroup: string | string[] = "common") => {
// 初始化资源配置
RES.loadConfig(ResJson);
console.log("初始化资源配置完成");
// 皮肤配置加载
RES.loadSkinConfig(SkinJson);
console.log("初始化皮肤配置完成");
if (typeof resGroup === "string") {
// 加载通用资源
await RES.loadGroup(resGroup);
}else if (Array.isArray(resGroup)) {
await Promise.all(resGroup.map(res => RES.loadGroup(res)))
}
console.log(`资源组${resGroup}加载完成`);
}
export const ResJson = {
"groups": [
{
"keys": "comCloseBtn.png,toastBg.png,waitingBg.png,waitingRot.png",
"name": "common",
"atlas": {
"waitingBg.png": {
"x": 2,
"y": 134,
"w": 160,
"h": 180,
"ox": 0,
"oy": 0,
"sw": 160,
"sh": 180,
"ro": true
},
"toastBg.png": {
"x": 2,
"y": 2,
"w": 460,
"h": 130,
"ox": 0,
"oy": 0,
"sw": 460,
"sh": 130,
"ro": false
},
"waitingRot.png": {
"x": 184,
"y": 194,
"w": 56,
"h": 56,
"ox": 0,
"oy": 0,
"sw": 56,
"sh": 56,
"ro": false
},
"comCloseBtn.png": {
"x": 184,
"y": 134,
"w": 58,
"h": 58,
"ox": 0,
"oy": 0,
"sw": 58,
"sh": 58,
"ro": false
}
}
},
{
"keys": "coin.svga,fudai.png,点中红包飘爱心.svga,点中飘金币.svga,红包1.png,红包2.png,红包3.png,金币.png",
"name": "game",
"atlas": {
"红包1.png": {
"x": 311,
"y": 152,
"w": 105,
"h": 134,
"ox": 0,
"oy": 0,
"sw": 105,
"sh": 134,
"ro": true
},
"fudai.png": {
"x": 311,
"y": 2,
"w": 148,
"h": 148,
"ox": 0,
"oy": 0,
"sw": 148,
"sh": 148,
"ro": false
},
"红包2.png": {
"x": 2,
"y": 234,
"w": 177,
"h": 150,
"ox": 0,
"oy": 0,
"sw": 177,
"sh": 150,
"ro": false
},
"金币.png": {
"x": 181,
"y": 259,
"w": 99,
"h": 75,
"ox": 0,
"oy": 0,
"sw": 99,
"sh": 75,
"ro": true
},
"红包3.png": {
"x": 2,
"y": 2,
"w": 307,
"h": 230,
"ox": 0,
"oy": 0,
"sw": 307,
"sh": 230,
"ro": false
}
}
}
],
"path": "https://yun.duiba.com.cn/db_games/activity/template/1706532299/resource/"
}
\ No newline at end of file
export const SkinJson = {
"x": 0,
"y": 0,
"type": "container",
"children": [
]
}
import { Panel } from "../../module/views/Panel";
// interface IConfirmPanel {
//
// resolve: Function;
// reject: Function;
// promise: Promise<any>;
//
// make(): Promise<any>;
//
// }
export default class ConfirmPanel extends Panel {
resolve: Function = null;
reject: Function = null;
promise: Promise<any> = null;
public makePromise(): Promise<any> {
this.promise = new Promise<any>((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
return this.promise;
}
}
import { RES } from "../../module/RES";
import { getLightBgTexture } from "./getLightBgTexture";
/**
* 旋转光
*/
export class Light extends FYGE.Sprite {
constructor() {
super();
this.texture = RES.getRes("light.png");
this.anchorTexture.set(0.5, 0.5);
this.addEventListener(FYGE.Event.ENTER_FRAME, () => {
this.rotation += 1;
}, this)
}
}
/**
* 自行生成的光
*/
export class RotateLight extends FYGE.Sprite {
constructor(
lightColor: string = "#fffbb0",
lightRadius: number = 425,
lightNum: number = 18,
bgColor: string = lightColor,
bgRadius: number = lightRadius - 25
) {
super();
this.texture = getLightBgTexture(
lightColor,
lightRadius,
lightNum,
bgColor,
bgRadius
);
this.anchorTexture.set(0.5, 0.5);
this.addEventListener(FYGE.Event.ENTER_FRAME, () => {
this.rotation += 1;
}, this)
}
}
\ No newline at end of file
import UI from "../tools/UI";
import TEXT_ALIGN = FYGE.TEXT_ALIGN;
import Container = FYGE.Container;
/**
* 纯色进度条
*/
export class ProgressBar extends Container {
/**
* 0到1的进度
*/
private _value = 0;
private upImage: FYGE.Graphics;
private progressTxt: FYGE.TextField;
private readonly maxLength: number;
constructor() {
super()
this.maxLength = 377//最大长度
this._value = 0;
this.upImage = UI.Graphics(this)
.beginFill(0xf8c862)
.drawRoundedRect(0, 0, this.value * this.maxLength, 19, 10)
.endFill();
this.progressTxt = UI.Txt(
this, "0%", 22, "#f8c862",
TEXT_ALIGN.CENTER, 80, (this.maxLength - 80) / 2, 36
);
}
get value() {
return this._value;
}
set value(v) {
if (v < 0) v = 0;
if (v > 1) v = 1;
this._value = v;
this.progressTxt.text = ((v * 100) >> 0) + "%";
const length = this._value * this.maxLength;
this.upImage.clear()
.beginFill(0xf8c862)
.drawRoundedRect(0, 0, length, 19, 10)
.endFill();
}
}
/**
* 传入文案和进度条图片
* 进度条图片位移,固定遮罩
* 貌似这样就不需要继承显示类了
*/
import Sprite = FYGE.Sprite;
import TextField = FYGE.TextField;
import Graphics = FYGE.Graphics;
import FrameAni = FYGE.FrameAni;
export class ProgressBarS {
/**
* 0到1的进度
*/
private _value = 0;
private upImage: Sprite;
private progressTxt: TextField;
private maxLength: number;
private oriX: number
constructor(upImage: Sprite, txt?: TextField) {
this.maxLength = upImage.width;//最大长度,直接取图片宽度
this.upImage = upImage;
this.progressTxt = txt;
this.oriX = upImage.x;
var delta = 0
//传入的也可能是帧动画,这样原点就有问题了
if (upImage instanceof FrameAni) delta = 0.5
//给图片加个矩形遮罩
this.upImage.mask = this.upImage.parent.addChild(new Graphics())
.beginFill(0xf8c862)
.drawRoundedRect(
upImage.x - upImage.width * delta,
upImage.y - upImage.height * delta,
upImage.width,
upImage.height,
111
)
.endFill();
this.value = 0;
}
get value() {
return this._value;
}
set value(v) {
if (v < 0) v = 0;
if (v > 1) v = 1;
this._value = v;
if (this.progressTxt) this.progressTxt.text = ((v * 100) >> 0) + "%";
this.upImage.x = this.oriX - (1 - this._value) * this.maxLength
}
}
// var aa = this.addChild(new RichText(
// [
// { text: "啊请问请问", style: { color: "#000000", size: 30 } },
// { text: "=2134324234啊请问请问", style: { color: "#ff0000", size: 30 } },
// { text: "驱蚊器问问", style: { color: "#000000", size: 30 } }
// ]
// ))
// aa.text = [
// { text: "啊请问请问", style: { color: "#000000", size: 30 } },
// { text: "=2134", style: { color: "#ff0000", size: 30 } },
// { text: "驱蚊器问问", style: { color: "#000000", size: 30 } }
// ]
// aa.position.set(375, 800);
// [{text: "测试",style:{color: ""}},{},{}]
import TextField = FYGE.TextField;
import Container = FYGE.Container;
interface IRichTextEle {
text: string,
style: { color: string, size: number }
}
export class RichText extends Container {
declare children : TextField[];
private static cache: FYGE.TextField[] = []
/**
*
* @param text
*/
constructor(text?: IRichTextEle[]) {
super()
if (text) this.text = text;
}
/**
* 水平对齐方式,默认居中
*/
get textAlign() {
return this._textAlign
}
set textAlign(value: FYGE.TEXT_ALIGN) {
if (this._textAlign !== value) {
this._textAlign = value;
this.adaptate();
}
}
private _textAlign: FYGE.TEXT_ALIGN = FYGE.TEXT_ALIGN.CENTER;
/**
* 垂直居中方式,默认居中
*/
get verticalAlign() {
return this._verticalAlign
}
set verticalAlign(value: FYGE.VERTICAL_ALIGN) {
if (this._verticalAlign !== value) {
this._verticalAlign = value;
this.adaptate();
}
}
private _verticalAlign: FYGE.VERTICAL_ALIGN = FYGE.VERTICAL_ALIGN.MIDDLE;
/**
* 文字间隙
*/
get gap(): number {
return this._gap;
};
set gap(value: number) {
if (this._gap != value) {
this._gap = value;
this.adaptate();
}
};
private _gap: number = 0;
/**
* 文本
*/
private _text: IRichTextEle[];
/**
* 按顺序
*/
get text(): IRichTextEle[] {
return this._text
}
/**
*
*/
set text(value: IRichTextEle[]) {
let i;
this._text = value;
const arr = value || [];
for (i = 0; i < arr.length; i++) {
const a = arr[i];
const c: TextField = this.children[i] || this.addChild(RichText.cache.shift() || new TextField());
c.text = a.text;
c.fillColor = a.style.color;
c.size = a.style.size;
}
//如果多了,去掉后面的,回收
if (this.children.length > arr.length) {
//移除后序
for (i = this.children.length - 1; i >= arr.length; i--) {
const c = this.children[i];
this.removeChild(c);
RichText.cache.push(c);
}
}
//适配
this.adaptate()
}
/**
* 适配,
*/
private adaptate() {
let i;
if (!this.children.length) return
var len = this.children.length;
//算总长度
var sum = 0;
for (var m = 0; m < len; m++) {
sum += this.children[m].textWidth;
}
sum += (len - 1) * this._gap;
//算出左边第一个元素的位置
var left: number;
if (this._textAlign == FYGE.TEXT_ALIGN.LEFT) {
left = 0
}
else if (this._textAlign == FYGE.TEXT_ALIGN.RIGHT) {
left = -sum
} else {
left = -sum / 2
}
var temSum = 0;
for (i = 0; i < this.children.length; i++) {
this.children[i].x = left + temSum
temSum += this.children[i].textWidth + this._gap;
}
var up: number;
if (this._verticalAlign == FYGE.VERTICAL_ALIGN.UP) {
up = 0
}
else if (this._verticalAlign == FYGE.VERTICAL_ALIGN.DOWN) {
up = -1
} else {
up = -1 / 2
}
for (i = 0; i < this.children.length; i++) {
this.children[i].y = this.children[i].textHeight * up;
}
}
}
//sdk
// <script src="//yun.duiba.com.cn/db_games/libs0924/howler.min.js"></script>
var resPath = "https://yun.duiba.com.cn/db_games/qx/hyundaiXXL/sound/";
var gameMusicBg = "https://yun.duiba.com.cn/aurora/assets/1f591de154f744a65f16fc2b86ae7cd069ac4421.mp3";
var boom = 'https://yun.duiba.com.cn/spark/assets/0cebbed9233d99ac4fb8a78d875f5efca9bad444.mp3';
var props = "https://yun.duiba.com.cn/spark/assets/34666d18dcc6c5054257c6914268f67c67bae49d.mp3";
var gold = "https://yun.duiba.com.cn/spark/assets/729a54f12f529cfef03db43715e0985d1f0d4f72.mp3";
export enum SoundType {
gameMusicBg = "gameMusicBg",
}
let isMuteStatus = false
let isPlayBg = false
export function cusPlaySound(soundType: number, loop: boolean = false, isMute: boolean = false) {
switch (soundType) {
case 1:
if (!isPlayBg) {
isPlayBg = true
playSound(gameMusicBg, loop, isMuteStatus)
}
break
case 2:
playSound(boom, loop, isMuteStatus)
break
case 3:
playSound(props, loop, isMuteStatus)
break
case 4:
playSound(gold, loop, isMuteStatus)
break
default:
break
}
// playSound(unionPath, loop);
}
/**
* 提前加载音频
* @param type
*/
export function preloadSound(type: SoundType) {
let src = resPath + type + ".mp3";
soundHash[src] = new Howl({
src: src,
preload: true,
});
}
/**
* 根据路径记录
*/
const soundHash: { [key: string]: Howl } = {};
export function playSound(src: string, loop: boolean = false, isMute: boolean = false) {
console.log('测试音效isMute', isMute);
let sound: Howl;
//循环的,且有缓存,取缓存的
if (soundHash[src] && loop) sound = soundHash[src]
//没有就新建
if (!sound) sound = new Howl({ src: [src], autoplay: false, loop });
//记录下,方便停止
soundHash[src] = sound;
//不循环删除缓存
if (!loop) sound.on('stop', function () { delete soundHash[src] });
if (isMute) {
// 静音
sound.stop()
} else {
//播放
console.log("播放")
sound.mute(false)
sound.play();
}
// console.log(sound)
//console.log('测试是否播放音效',src);
//返回一个,可以自行控制
return sound;
}
export function stopSound(src: string) {
if (soundHash[src]) soundHash[src].stop();
}
export function muteAllSound() {
isMuteStatus = false
console.log(isMuteStatus)
for (let key in soundHash) soundHash[key].mute(false);
}
export function resumeAllSound() {
isMuteStatus = true
console.log(isMuteStatus)
for (let key in soundHash) soundHash[key].mute(true);
}
export function stopAllSound() {
for (let key in soundHash) soundHash[key].stop();
}
export function playAllSound() {
for (let key in soundHash) soundHash[key].play();
}
//设置隐藏属性和改变可见属性的事件的名称
let hidden: string, visibilityChange: string;
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document['msHidden'] !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
} else if (typeof document['webkitHidden'] !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}
const handleVisibilityChange = () => {
if (document.visibilityState == "visible") {
playAllSound();
console.log("网页显示")
}
else if (document.visibilityState == "hidden") {
stopAllSound()
console.log("网页隐藏")
}
};
document.addEventListener(
visibilityChange,
handleVisibilityChange,
false
);
window.onbeforeunload = function () {
//发接口
}
// window.addEventListener('beforeunload', ()=>{
// //发接口出去,
// })
// document.body['onbeforeunload'] = () => {
// }
/**
*
* @param dis
* @param zoomCenter 是否设定中心缩放,默认true,为了自行确定锚点的对象
*/
export function addBreathing(dis: FYGE.DisplayObject, zoomCenter: boolean = true) {
if (zoomCenter) {
dis.anchorX = dis.width / 2;
dis.anchorY = dis.height / 2;
}
FYGE.Tween.get(dis, { loop: true })
.to({ scaleX: 1.1, scaleY: 1.1 }, 1000)
.to({ scaleX: 1, scaleY: 1 }, 1000)
}
/**
*
* @param dis
* @param zoomCenter 是否设定中心缩放,默认true,为了自行确定锚点的对象
*/
import DisplayObject = FYGE.DisplayObject;
import MouseEvent = FYGE.MouseEvent;
import Tween = FYGE.Tween;
export function addClickZoom(dis: DisplayObject, zoomCenter: boolean = true) {
if (zoomCenter) {
dis.anchorX = dis.width / 2;
dis.anchorY = dis.height / 2;
}
dis.addEventListener("onMouseDown", _mouseEvent, dis)
.addEventListener("onMouseUp", _mouseEvent, dis)
.addEventListener("onMouseOut", _mouseEvent, dis);
let s = dis;
function _mouseEvent(e: MouseEvent) {
if (e.type == MouseEvent.MOUSE_DOWN) {
Tween.removeTweens(s);
Tween.get(s).to({ scaleX: 0.9, scaleY: 0.9 }, 50);
} else {
Tween.removeTweens(s);
Tween.get(s).to({ scaleX: 1, scaleY: 1 }, 50);
}
}
return dis;
}
/**
* 倒计时
* @param time 毫秒计算
* @param onChange 根据时间倒计时的执行函数
*/
export function countDown(time: number, onChange: (t: number) => void) {
const timeObj = { a: time };
FYGE.Tween.get(timeObj, {
onChange: () => {
onChange(timeObj.a)
// this.timeTxt.text = "" + Math.round(timeObj.a / 1000) + "s"
// if (timeObj.a < 100) {
// FYGE.Tween.removeTweens(timeObj)
// callback()
// }
}
})
.to({ a: 0 }, time)
//返回一个,可以中途取消
return timeObj
}
/**
* 中断倒计时
* @param timeObj
*/
export function clearCountDown(timeObj) {
if (!timeObj) return
FYGE.Tween.removeTweens(timeObj)
}
const cache: {
[key: string]: FYGE.Texture
} = {}
/**
*
* @param lightColor 颜色
* @param lightRadius 光环半径
* @param lightNum 光环扇形数量
* @param bgColor 背光颜色
* @param bgRadius 背光半径
*/
export function getLightBgTexture(
lightColor: string = "#fffbb0",
lightRadius: number = 425,
lightNum: number = 18,
bgColor: string = lightColor,
bgRadius: number = lightRadius - 25
) {
const cacheKey = `${lightColor}_${lightRadius}_${lightNum}_${bgColor}_${bgRadius}`;
//缓存过就返回
if (cache[cacheKey]) return cache[cacheKey];
const canvas = FYGE.createCanvas()// document.createElement("canvas");
canvas.width = canvas.height = lightRadius * 2;
const x = lightRadius, y = x;
const ctx = canvas.getContext("2d");
//最大值18,否则开放每个灯光角度
lightNum = Math.floor(Math.min(18, lightNum));
//背景的光晕
var colorObj = ctx.createRadialGradient(x, y, 0, x, y, bgRadius);
colorObj.addColorStop(0, bgColor);
colorObj.addColorStop(1, bgColor + "00");
ctx.fillStyle = colorObj;
ctx.beginPath();
ctx.arc(x, y, lightRadius, 0, 2 * Math.PI)
ctx.fill()
//径向的光
var colorObj = ctx.createRadialGradient(x, y, 0, x, y, lightRadius);
colorObj.addColorStop(0, lightColor);
colorObj.addColorStop(1, lightColor + "00");
ctx.fillStyle = colorObj;
ctx.beginPath();
var anglePer = Math.PI / 12;
var delta = Math.PI * 2 / lightNum;
for (var i = 0; i < lightNum; i++) {
ctx.moveTo(x, y)
ctx.arc(x, y, lightRadius, Math.PI * 1.5 - anglePer / 2 + delta * i, Math.PI * 1.5 + anglePer / 2 + delta * i)
}
ctx.fill();
//缓存
cache[cacheKey] = FYGE.Texture.fromCanvas(canvas);
return cache[cacheKey];
}
\ No newline at end of file
/*
* usePool.ts
* Created by 还有醋v on 2022/6/1.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
/**
* 使用对象池能力
* @param cls
*/
export function usePool<T extends {new (...args: any[]): any}>(cls: T) {
return class nCls extends cls {
static _pool: T[] = [];
static get(): T {
return this._pool.splice(0, 1)[0] || new nCls();
}
static put(obj: T) {
return this._pool.push(obj);
}
};
}
/*
* index.ts
* Created by 还有醋v on 2022/6/2.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
import EventDispatcher = FYGE.EventDispatcher;
export * from "./Game";
/**
* 从config导出setConfig方法
*/
export * from "./Config";
/**
* 导出事件和事件收发器
*/
export enum GAME_EVENT {
READY = "READY", // 初始化完成
START_GAME = "START_GAME",
END_GAME = "END_GAME",
ADD_SCORE = "ADD_SCORE",
ON_SHOW = 'ON_SHOW', // 页面显示
ON_HIDE = 'ON_HIDE', // 页面隐藏
}
export const GDispatcher = new EventDispatcher();
export {preloadRes} from './PreloadRes'
import { Scene } from "../../module/views/Scene";
import Clock from "../tools/Clock";
import gameConfig from "../Config";
import { GAME_EVENT, GDispatcher } from "../index";
import RainObj from "./RainObj";
import UI from "../tools/UI";
import { RES } from "../../module/RES";
import Event = FYGE.Event;
import Container = FYGE.Container;
import SvgaAni = FYGE.SvgaAni;
export class GameScene extends Scene {
get groupNames(): string[] {
return ['game'];
}
clock: Clock = new Clock();
/**
* 是否暂停游戏
* @type {boolean} true 暂停 false 不暂停
*/
isPause: boolean = true;
/**
* 经过了多少时间
* @type {number}
*/
eTime: number = 0;
objList: RainObj[] = [];
// 掉落物层
objCtn: Container;
// 特效层
effectCtn: Container;
initUi() {
this.objCtn = UI.Ctn(this);
this.effectCtn = UI.Ctn(this);
this.effectCtn.mouseEnable = this.effectCtn.mouseChildren = false;
}
async start(data?: any) {
super.start(data);
GDispatcher.dispatchEvent(GAME_EVENT.READY);
}
/**
* 添加特效
* @param x
* @param y
*/
addEffect(x, y, name) {
const svga = {
"红包1.png": "点中红包飘爱心.svga",
"红包2.png": "点中飘金币.svga",
"红包3.png": "点中红包飘爱心.svga",
"金币.png": "点中飘金币.svga",
"fudai.png": "点中红包飘爱心.svga",
}[name] || "点中红包飘爱心.svga";
const boomEffect = this.effectCtn.addChild(new SvgaAni(RES.getRes(svga)));
const { videoWidth, videoHeight, totalFrames } = boomEffect;
boomEffect.position.set(x - videoWidth / 2, y - videoHeight / 2);
boomEffect.startAniRange(0, totalFrames, 1, () => {
this.effectCtn.removeChild(boomEffect);
});
}
/**
* 添加掉落物
*/
addObj() {
const obj = RainObj.get();
obj.reset();
this.objCtn.addChild(obj);
this.objList.push(obj);
}
/**
* 删除掉落物
*/
removeObj(obj) {
this.objList.splice(this.objList.indexOf(obj), 1);
this.objCtn.removeChild(obj);
RainObj.put(obj);
}
initEvents() {
super.initEvents();
GDispatcher.addEventListener(GAME_EVENT.START_GAME, this.startGame, this);
GDispatcher.addEventListener(GAME_EVENT.END_GAME, this.endGame, this);
this.addEventListener(Event.ENTER_FRAME, this.onUpdate, this);
}
removeEvents() {
super.removeEvents();
GDispatcher.removeEventListener(GAME_EVENT.START_GAME, this.startGame, this);
GDispatcher.removeEventListener(GAME_EVENT.END_GAME, this.endGame, this);
this.removeEventListener(Event.ENTER_FRAME, this.onUpdate, this);
}
startGame() {
// 已经开始了
if (!this.isPause) return console.warn("已经开始了");
this.isPause = false;
this.eTime = 0;
}
endGame() {
if (this.isPause) return console.warn("已经结束了");
this.objList.forEach((obj) => {
this.removeObj(obj);
});
this.objList.length = 0;
this.objCtn.removeAllChildren();
this.isPause = true;
}
onUpdate() {
// 暂停
if (this.isPause) return;
const { interval, dropSpeed } = gameConfig;
const { objList, clock } = this;
let dt = clock.getDelta();
if (dt > 0.067) dt = 0.067;
this.eTime += dt;
if (this.eTime > interval) {
this.eTime = interval - this.eTime;
this.addObj();
}
for (let i = objList.length - 1; i >= 0; i--) {
const obj = objList[i];
obj.y += dropSpeed * dt;
if (obj.y > 1724) {
this.removeObj(obj);
}
}
}
}
/*
* RainMgr.ts
* Created by 还有醋v on 2022/6/1.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
import Container = FYGE.Container;
import gameConfig from "../Config";
import UI from "../tools/UI";
import Sprite = FYGE.Sprite;
import MouseEvent = FYGE.MouseEvent;
import {GameScene} from "./GameScene";
import {GAME_EVENT, GDispatcher} from "../index";
import {getCurrentScene} from "../../module/ctrls";
export default class RainObj extends Container {
static _pool: RainObj[] = [];
static get(): RainObj {
return this._pool.splice(0, 1)[0] || new RainObj();
}
static put(obj: RainObj) {
return this._pool.push(obj);
}
private image: Sprite = null;
constructor() {
super();
this.init();
}
reset() {
const { width, height } = this.image;
const x = width / 2 + Math.random() * (750 - width);
this.position.set(x, -Math.random() * 200 - height);
this.rotation = Math.random() * 50 + 10;
}
init() {
const sp = gameConfig.rainObj[Math.random() * gameConfig.rainObj.length >> 0];
this.name = sp;
this.image = UI.Sp(this, sp);
this.image.anchorTexture.set(0.5, 0.5);
// remove
this.addEventListener(MouseEvent.MOUSE_DOWN, (e) => {
(getCurrentScene() as GameScene).removeObj(this);
(getCurrentScene() as GameScene).addEffect(this.x, this.y, this.name);
GDispatcher.dispatchEvent(GAME_EVENT.ADD_SCORE, {type: 'redBag'})
});
}
}
export default class Clock {
startTime = 0;
oldTime = 0;
elapsedTime = 0;
running = false;
constructor(
public autoStart = true
) {
}
start() {
this.startTime = (typeof performance === 'undefined' ? Date : performance).now();
this.oldTime = this.startTime;
this.elapsedTime = 0;
this.running = true;
}
stop() {
this.getElapsedTime();
this.running = false;
this.autoStart = false;
}
getElapsedTime() {
this.getDelta();
return this.elapsedTime;
}
getDelta() {
let diff = 0;
if (this.autoStart && !this.running) {
this.start();
return 0;
}
if (this.running) {
const newTime = (typeof performance === 'undefined' ? Date : performance).now();
diff = (newTime - this.oldTime) / 1000;
this.oldTime = newTime;
this.elapsedTime += diff;
}
return diff;
}
}
import { RES } from "../../module/RES";
import { layers } from "../../module/views/layers";
import Container = FYGE.Container;
import TEXT_ALIGN = FYGE.TEXT_ALIGN;
import TextField = FYGE.TextField;
import Texture = FYGE.Texture;
import Tween = FYGE.Tween;
/**
* 定制,记录一些全局量和通用方法
*/
export class Tools {
/**
* 缓存key
*/
static cacheKey: string = "cow_xiaobujian"
/************ 其他 ************/
/**
* 修改皮肤上的文本对齐方式,原先默认是左的,多汗行的时候计算有误,待查
* @param text
* @param align
* @param textWidth
*/
static changeTextAlign(text: TextField, align: TEXT_ALIGN, textWidth?: number) {
if (align == TEXT_ALIGN.LEFT) return;
text.textAlign = align;
//没有就原先的
textWidth = textWidth || text.textWidth;
//修改位置
if (align == TEXT_ALIGN.CENTER) text.x -= (textWidth - text.textWidth) / 2;
if (align == TEXT_ALIGN.RIGHT) text.x -= textWidth - text.textWidth
text.textWidth = textWidth;
}
/**
* 延时防连点
* @param target
* @param {number} delay 默认2000毫秒
*/
static btnDelay(target: Container, delay: number = 2000) {
target.mouseEnable = false;
target.mouseChildren = false;
setTimeout(() => {
target.mouseEnable = true;
target.mouseChildren = true;
}, delay);
}
/**
* 根据名字获取0到9的贴图
* 位图字每次都写太烦了
* @param name
*/
static getNumTextures(name: string): { [key: number]: Texture } {
const arr = {};
for (let i = 0; i <= 9; i++) arr[i] = RES.getRes(name + i + ".png")
return arr
}
/**
* 获得距离底部的百分比高度,还要减个自身的高度,自行处理
* @param {number} percent 百分比
* @returns {number}
*/
static getAdjustBottomHeight(percent: number): number {
return layers.stageHeight - layers.stageHeight * percent + layers.stageOffsetY;//stageOffsetY加不加取决于页面适配类型
}
/**
* 获得距离顶部的百分比高度
* @param {number} percent 百分比
* @returns {number}
*/
static getAdjustTopHeight(percent: number): number {
return layers.stageHeight * percent + layers.stageOffsetY;//stageOffsetY加不加取决于页面适配类型
}
}
/**
* 从数组里随机取元素
* @param arr
* @param count
*/
export function getRandomArrayElements(arr, count) {
if (arr.length <= count) return arr;
let shuffled = arr.slice(0), i = arr.length, min = i - count, temp, index;
while (i-- > min) {
index = (i + 1) * Math.random() >> 0;
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(min);
}
/**
* 数字补0
* @param num 数字
* @param length 位数
*/
export function prefixInteger(num: number, length: number) {
return (Array(length).join('0') + num).slice(-length);
}
export function numLimit(num: number, min: number, max: number): number {
if (num > max) return max;
else if (num < min) return min;
return num;
}
export async function sleep(time: number): Promise<void> {
return new Promise((resolve) => {
Tween.get(FYGE)
.wait(time)
.call(resolve)
});
}
/*
* UI.ts
* Created by 还有醋v on 2021/5/12.
* Copyright © 2021 haiyoucuv. All rights reserved.
*/
import { RES } from "../../module/RES";
import Container = FYGE.Container;
import Button = FYGE.Button;
import MouseEvent = FYGE.MouseEvent;
import Sprite = FYGE.Sprite;
import TEXT_ALIGN = FYGE.TEXT_ALIGN;
import TextField = FYGE.TextField;
import Shape = FYGE.Shape;
import Lottie = FYGE.Lottie;
import Texture = FYGE.Texture;
import Graphics = FYGE.Graphics;
import BitmapText = FYGE.BitmapText;
export default class UI {
/**
* 按钮
* @param {FYGE.Container} parent
* @param {string} enImg
* @param {Function} func
* @param that
* @param {number} x
* @param {number} y
* @param {number} anchorX
* @param {number} anchorY
* @param {string} tImg
* @param {string} disImg
* @returns {FYGE.Button}
* @constructor
*/
static Btn(
parent: Container,
enImg: string,
func: Function,
that,
x: number = 0, y: number = 0,
anchorX?: number, anchorY?: number,
tImg: string = enImg, disImg: string = enImg
): Button {
const btn = new Button(RES.getRes(enImg), RES.getRes(tImg), RES.getRes(disImg));
btn.addEventListener(MouseEvent.CLICK, func, that);
btn.position.set(x, y);
anchorX !== undefined && (btn.anchorX = anchorX);
anchorY !== undefined && (btn.anchorY = anchorY);
parent && parent.addChild(btn);
return btn;
}
/**
* 图片
* @param {FYGE.Container} parent
* @param {string} imageName
* @param {number} x
* @param {number} y
* @returns {FYGE.Sprite}
* @constructor
*/
public static Sp(
parent: Container,
imageName: string | Texture,
x: number = 0, y: number = 0
): Sprite {
let sprite;
if (imageName instanceof Texture) {
sprite = new Sprite(imageName);
} else {
const texture = RES.getRes(imageName);
if (texture) {
sprite = new Sprite(texture);
} else {
sprite = Sprite.fromUrl(imageName);
}
}
sprite.position.set(x, y);
parent && parent.addChild(sprite);
return sprite;
}
/**
* Container
* @param {Container} parent
* @param {number} x
* @param {number} y
* @returns {Container}
* @constructor
*/
public static Ctn(
parent: Container,
x: number = 0, y: number = 0
): Container {
const ctn = new Container();
ctn.position.set(x, y);
ctn && parent.addChild(ctn);
return ctn;
}
/**
* 文本
* @param {FYGE.Container} parent
* @param {string} txt
* @param {number} size
* @param {string} color
* @param {FYGE.TEXT_ALIGN} align
* @param {number} textWidth
* @param {number} x
* @param {number} y
* @param bold
* @returns {FYGE.TextField}
*/
public static Txt(
parent: Container,
txt: string,
size: number,
color: string = "#000000",
align: TEXT_ALIGN = TEXT_ALIGN.LEFT,
textWidth: number = 0,
x: number = 0,
y: number = 0,
bold: boolean = false
): TextField {
const text = new TextField();
text.fillColor = color;
text.size = size;
textWidth && (text.textWidth = textWidth);
text.textAlign = align;
text.position.set(x, y);
text.text = txt;
text.bold = bold
parent && parent.addChild(text);
return text;
}
public static Rect(
parent: Container,
width: number,
height: number,
color: number = 0xff0000,
radius: number = 0,
x: number = 0,
y: number = 0,
alpha: number = 1,
): Shape {
const shape = new Shape();
// shape.clear();
shape.beginFill(color);
if (!radius) {
shape.drawRect(0, 0, width, height);
} else {
shape.drawRoundedRect(0, 0, width, height, radius);
}
shape.endFill();
shape.alpha = alpha;
shape.position.set(x, y);
parent && parent.addChild(shape);
return shape;
}
public static Lottie(parent: Container, data: any, x: number = 0, y: number = 0) {
const lottie = new Lottie(data);
lottie.x = x
lottie.y = y
parent && parent.addChild(lottie);
return lottie;
}
public static Shape(
parent: Container,
x: number = 0, y: number = 0
): Shape {
const shape = new Shape();
shape.position.set(x, y);
parent && parent.addChild(shape);
return shape;
}
public static Graphics(
parent: Container,
x: number = 0, y: number = 0
): Graphics {
const graphics = new Graphics();
graphics.position.set(x, y);
parent && parent.addChild(graphics);
return graphics;
}
public static BitTxt(
parent: Container,
texture: { [key: string]: Texture },
text: string = "",
x: number = 0,
y: number = 0,
scaleX: number = 1,
scaleY: number = 1,
gap = 0
): BitmapText {
const bitTxt = new BitmapText(texture);
bitTxt.position.set(x, y);
bitTxt.scale.set(scaleX, scaleY);
bitTxt.text = text;
bitTxt.gap = gap;
parent && parent.addChild(bitTxt);
return bitTxt;
}
}
import { showToast } from "../../module/ctrls";
import { ajax, jsonp } from "../../module/ajax";
import { GDispatcher } from "../index";
import { getUrlParams } from "../../module/tools/WebTool";
//////////////星速台接口方法集成
/**
* web接口枚举,mock 文件名类似aaa/homeInfo.do
*/
export enum WebNetName {
/**
* 首页
* 参数a 参数b
*/
index = "/projectx/{projectId}/game/index.do",
/**
* 参与
*/
join = "/projectx/{projectId}/game/join.do",
/**
* 获取结果
*/
queryResult = "/projectx/{projectId}/game/queryResult.do",
/**
* 获取规则
*/
projectRule = "/projectx/{projectId}/projectRule.query"
}
//返回数据类型
interface dataOut {
success: boolean,
data?: any
code?: string,
message?: string
}
//记录数据
let dataRecord: {
[name: string]: any
} = {};
/**
* 发送接口
* @param netName
* @param parameter
* @param callback
* @param hideMsg
* @param isGet
* @param headers
*/
export function sendWebNet(
netName: WebNetName,
parameter?: any,
callback?: (success: boolean, res?: dataOut) => void,
hideMsg: boolean = false,
isGet: boolean = true,//这两个参数基本不设置,放后面吧
headers?: any,
): Promise<dataOut> {
return new Promise((resolve, reject) => {
if (__ENV__ == "development") { // TODO 编译后提供的变量
let path = netName.split('{projectId}/')[1];//后缀名字之前的是文件夹,mock里结构
if (path.indexOf('/') <= -1) path = `projectX/${path}`;
const url = "../../mock/webNet/" + path + ".json";
fetchAsync(url)
.then((data) => {
//清除超时
// clearWait(waitObj)
//记录数据
dataRecord[netName] = data;
//统一错误信息提示
if (!hideMsg && !data.success) showToast(data.message || "活动太火爆了,请稍后再试~");
//回调
callback && callback(data.success, data);
resolve(data)
console.log(
`\n%c[ mock ]\n`
+ `NAME : ${netName} \n`
+ `STATE : %o \n`
+ `PARAM : %o \n`
+ `%cDATA : %o \n`
, `${data.success ? 'color:green' : 'color:red'}`
, data.success
, parameter
, `${data.success ? 'color:green' : 'color:red'}`
, data
);
}, () => {
})
return
}
//网络请求
ajax({
url: netName.replace("{projectId}", getProjectId()), //请求地址
type: isGet ? 'GET' : "POST", //请求方式
data: parameter || {}, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
headers: headers,
success: function (response) {
//发现有些接口成功了,但是response为空
response = response || {}
//记录数据
dataRecord[netName] = response;
//统一错误信息提示,
if (!hideMsg && !response.success) {
showToast(response.message || "活动太火爆了,请稍后再试~");
}
callback && callback(response.success, response)
resolve(response)
console.log(
`\n%c[ request ]\n`
+ `NAME : ${netName} \n`
+ `STATE : %o \n`
+ `PARAM : %o \n`
+ `%cDATA : %o \n`
, `${response.success ? 'color:green' : 'color:red'}`
, response.success
, parameter
, `${response.success ? 'color:green' : 'color:red'}`
, response
);
},
error: function (status) {
if (!hideMsg) showToast("网络超时");
callback && callback(false)
resolve({ success: false });
console.log("接口" + netName + ":网络超时");
},
})
})
}
/**
* 获取数据
* @param netName
*/
export function getWebData(netName: WebNetName): dataOut {
return dataRecord[netName] || null;
}
//销毁数据
export function destroyWebNetData() {
dataRecord = {}
}
async function fetchAsync(url: string) {
// await response of fetch call
let response = await fetch(url);
// only proceed once promise is resolved
let data = await response.json();
// only proceed once second promise is resolved
return data;
}
const projectxString = "projectx/";
let projectId: string;
/**
* 获取链接上的projectId
*/
export function getProjectId(): string {
if (projectId) return projectId;
let windowUrl = window.location.href;
let splitArr = windowUrl.split(projectxString);
if (splitArr.length != 2) {
return projectId = "projectId"
}
let start = windowUrl.indexOf(projectxString) + projectxString.length;
let end = splitArr[1].indexOf("/");
return projectId = windowUrl.substr(start, end);
}
//这个临时,如星速台链接有变,注意
var isProd = location.href.indexOf(".com.cn/projectx") >= 0;
/**
* 刷新星速台tokenkey,注意多活动跳转手动执行一边
* @param callback
*/
export function refreshPxTokenKey(callback?: (success: boolean) => void) {
if (isProd) {//线上
var head = document.getElementsByTagName("head")[0];
const scriptEl = document.createElement('script');
scriptEl.src = "getTokenKey?_=" + Date.now();
scriptEl.onload = function () {
head.removeChild(scriptEl);
callback && callback(true)
};
scriptEl.onerror = function () {
head.removeChild(scriptEl);
callback && callback(false)
};
head.appendChild(scriptEl);
} else {//本地环境
callback && callback(true)
}
}
//执行一次
refreshPxTokenKey();
/**
* 获取星速台token
* @param callback
*/
export function getPxToken(callback: (msg: string, token?: string) => void) {
if (!isProd) {//本地环境
callback(null, "token")
return
}
if (!window["ohjaiohdf"]) {
callback("need reload")
return
}
var xml = new XMLHttpRequest;
xml.open("get", "getToken?_t=" + Date.now(), !0);
xml.onreadystatechange = function () {
if (xml.readyState === 4 && xml.status === 200) {
var e = JSON.parse(xml.response);
if (e.success) {
window.eval(e.data);
callback(null, window["ohjaiohdf"]());
} else {
var msg = (() => {
switch (e.code) {
case "100001":
return "need login"
case "100024":
return "state invalid"
default:
return e.code
}
})();
callback(msg);
}
}
}
xml.onerror = function () {
callback("net error")
};
xml.onloadend = function () {
xml.status === 404 && callback("net error")
};
xml.send()
}
export enum LOG_TYPE {
EXPOSURE = 'exposure',
CLICK = 'click',
}
/**
* 埋点 sendLog(LOG_TYPE.EXPOSURE,"4")
* 注意点击埋点前必有曝光埋点
* @param type
* @param data
*/
export function sendLog(type: LOG_TYPE | 'exposure' | 'click', area: number) {
const projectID = getProjectId();
const appID = getUrlParams("appID");
//给个提示
if (!appID) console.error("appID不存在,检查链接")
var dpm = `${appID || 'appID'}.110.${area}.1`;// TODO appID注意默认写死一个,已防链接没有
var dcm = `202.${projectID || 'projectID'}.0.0`;
//看需求
// var dom = `${isWxClient() ? '2' : '1'}.0.0.0`;
let params: any = {
dpm,
dcm,
appId: appID
};
//看需求
// if (dom) params.dom = dom;
let isExposure = (type == LOG_TYPE.EXPOSURE);
if (isExposure) {
//曝光
jsonp('//embedlog.duiba.com.cn/exposure/standard', params);
} else {
//点击
jsonp('/log/click', params);
}
// console.log('try log', {type, ...params});
}
/**
* 根据规则id获取奖品列表
* @param strategyId 规则id
* @param optionId 不传表示返回所有奖品
*/
export function queryPrizeList(strategyId: string, optionId?: string): Promise<dataOut> {
let url = `/projectx/${getProjectId()}/${strategyId}.query`;
return new Promise((resolve) => {
if (window.location.port == "8080") {//本地环境
resolve({//自定义数据。暂时这样
"success": true,
"message": "consequat ea",
"data": [
{
"prizeType": "dolore culpa in tempor",
"name": "ka3",
"refType": "Excepteur adipisicing sint",
"icon": "//yun.duiba.com.cn/spark/assets/58184d8d965c556b412026acf7a5d5d9e7a975f5.png",
"index": "Ut in pariatur",
"id": "et",
"refId": "minim culpa veniam aliqua ut",
"prizeId": "aa",
"icon2": "aliquip consectetur laborum Duis"
}
],
"code": "fugiat velit in esse aute"
})
} else {
ajax({
url,
type: 'GET',
data: optionId ? { optionId } : {},
dataType: "json",
async: true,
success: function (response) {
resolve(response)
},
error: function () {
resolve({ success: false })
}
})
}
})
}
////////////webview通信的范例,小程序端的是天猫精灵的例子
//天猫的webview数据请求方式 webview和小程序通讯方式,别忘了html上加sdk
//<script type="text/javascript" src="https://appx/web-view.min.js"></script>
export enum TmallNetName {
getAppData = "mine.getAppData",
/**
* 监听声音类型
*/
getVoiceType = "mine.getVoiceType",
}
//淘宝小程序全局
const my = window["my"];
if (FYGE.getEnv() == "web" && my) {//小程序webview时
//接收数据
my.onMessage = function (e) {
console.log("返回数据", e.netName, e.data)
//记录数据
// data[e.netName] = e.data;
//触发事件,会考虑单独发过来的事件
GDispatcher.dispatchEvent(e.netName, e.data)
}
}
export function sendTmallNet(
netName: TmallNetName,
parameter?: any,
callback?: (success: boolean, res?: dataOut) => void,
): Promise<dataOut> {
console.log("发送数据", netName, parameter)
return new Promise((resolve, reject) => {
if (window["development"]) {
var url = "../../mock/miniTb/" + netName + ".json"
fetchAsync(url)
.then((data) => {
//回调
callback && callback(data.success, data);
resolve(data);
}, () => {
callback(false);
})
return
}
if (FYGE.getEnv() == "web" && !my) {//临时处理
if (netName == TmallNetName.getAppData) {
var d = {
success: true,
data: {
avatar: "https://source.unsplash.com/user/erondu/76x76",
userNick: "驱蚊器委屈委"
}
}
callback && callback(true, d);
resolve(d);
}
return
}
//向小程序发信息
my.postMessage({
netName: netName,
parameter: parameter
});
//事件回调
let fun = function (e: { type: string, data: dataOut }) {
var d = e.data;
GDispatcher.removeEventListener(netName, fun);
callback && callback(d.success, d);
resolve(d);
}
//加事件
GDispatcher.addEventListener(netName, fun);
})
}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>new_game_template</title>
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="full-screen" content="true"/>
<meta name="screen-orientation" content="portrait"/>
<meta name="x5-fullscreen" content="true"/>
<meta name="360-fullscreen" content="true"/>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<!--<script crossorigin src="//yun.duiba.com.cn/db_games/libs220606/react/react.development.js"></script>-->
<script crossorigin src="//yun.duiba.com.cn/db_games/libs220606/react/react.production.min.js"></script>
<!--<script crossorigin src="//yun.duiba.com.cn/db_games/libs220606/react/react-dom.development.js"></script>-->
<script crossorigin src="//yun.duiba.com.cn/db_games/libs220606/react/react-dom.production.min.js"></script>
<!-- polyfill -->
<script src="//yun.duiba.com.cn/db_games/libs0924/polyfill_220525.js" crossorigin="anonymous"></script>
<!-- 渲染引擎 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge2044.min.js" crossorigin="anonymous"></script>
<!--<script src="libs/fyge.min.js" crossorigin="anonymous"></script>-->
<!-- svga解析库 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script>
<!-- 放声音的 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/howler.min.js" crossorigin="anonymous"></script>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script src="./debug/output.js" crossorigin="anonymous"></script>
</body>
</html>
{
"name": "test",
"version": "1.0.0",
"description": "test",
"scripts": {
"testDev": "rollup -c rollup.test.mjs -w"
},
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@babel/core": "^7.18.2",
"@babel/preset-env": "^7.18.2",
"@babel/preset-react": "^7.17.12",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.1.1",
"less": "^4.1.2",
"less-loader": "^11.0.0",
"rollup": "^2.61.1",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-progress": "^1.1.2",
"rollup-plugin-serve": "^1.1.0",
"rollup-plugin-styles": "^4.0.0"
},
"author": "haiyoucuv",
"license": "ISC"
}
/*
* rollup.test.mjs
* Created by 还有醋v on 2022/6/6.
* Copyright © 2021 haiyoucuv. All rights reserved.
*/
import json from "@rollup/plugin-json";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import livereload from "rollup-plugin-livereload";
import progress from "rollup-plugin-progress";
import babel from "@rollup/plugin-babel";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import styles from "rollup-plugin-styles";
export default {
input: "src/app.jsx",
cache: true,
output: {
file: "debug/output.js",
format: "umd",
sourcemap: true,
},
external: [
'react',
'react-dom',
'classname',
'**/node_modules/**'
],
plugins: [
peerDepsExternal(),
progress(),
styles(),
babel.babel({
presets: [
"@babel/preset-env",
"@babel/preset-react"
],
babelHelpers: "bundled"
}),
resolve({
jsnext: true,
preferBuiltins: true,
browser: true,
extensions: [".js", ".jsx"],
}),
commonjs({
extensions: [".js", ".jsx"],
}),
json(),
livereload(),
],
};
/*
* GamePage.jsx
* Created by 还有醋v on 2022/6/6.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
import React, { Component } from 'react';
import { Game, setConfig, GDispatcher, GAME_EVENT, preloadRes } from "../../../debug/output.module";
import './GamePage.less';
export default class GamePage extends Component {
canvas = React.createRef();
game = null;
async componentDidMount() {
// 作为模块使用预加载资源
await preloadRes('game');
this.game = new Game(this.canvas.current);
// 注册触摸事件
this.game.initWebEvent();
// 设置参数
setConfig({
dropSpeed: 400,
interval: 1,
});
// 等待READY事件表示可以开始游戏
GDispatcher.once(GAME_EVENT.READY, () => {
});
}
componentWillUnmount() {
this.game.destroy();
}
handleStartGame = () => {
// 触发开始游戏事件
GDispatcher.dispatchEvent(GAME_EVENT.START_GAME);
}
render() {
return <div
className="game-page"
ref={(div) => this.div = div}
>
<button onClick={this.handleStartGame}>开始游戏</button>
<canvas ref={this.canvas} style={{width:'100%',height:'100%'}} />
</div>
}
}
/*
* Game.less
* Created by 还有醋v on 2022/6/6.
* Copyright © 2022 haiyoucuv. All rights reserved.
*/
.game-page{
width: 100%;
height: 100%;
}
import GamePage from "./GamePage/GamePage";
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./app.less";
class App extends Component {
componentDidMount() {
}
render() {
return <GamePage/>;
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
* {
margin: 0;
padding: 0;
}
html,
body {
font-size: 24px;
width: 100%;
height: 100%;
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
overflow: hidden;
}
{
"compilerOptions": {
"experimentalDecorators": true,
"module": "ESNext",
"target": "ESNext",
"noImplicitAny": false,
"sourceMap": true,
"allowJs": true,
"noUnusedLocals": false,
"moduleResolution": "Node",
"removeComments": true,
"outDir": "dist",
/*"outFile": "./index.js",*/
"lib": [
"es5",
"dom",
"es2015.promise"
]
},
"exclude": [
"node_modules"
]
}
# 开发模版使用文档
### 文件目录
└── template \
├── config \
├── debug 不要管它 \
├── lotties 存放lottie文件 \
├── mock mock文件夹 \
├── module \
├── node_modules \
├── released 发布目录 \
├── resource 资源目录 \
├── scripts 脚本目录 \
├── test 测试目录 \
│ ├── debug 不要管它 \
│ ├── src 代码目录 \
│ ├── index.html 代码目录 \
│ └── rollup.test.mjs \
├── src 代码目录 \
│ ├── index.ts 主要导出 \
│ ├── Game.ts
│ ├── ResJson.ts 自动生成 \
│ └── SkinJson.ts 自动生成 \
├── .gitignore \
├── index.html html模版 \
├── project.json cdn配置 \
├── README.md \
├── rollup.dev.mjs \
├── rollup.prod.mjs \
└── 开发模版使用文档.md \
## 启动项目
`npm run dev`
访问 [http://localhost:8080/](http://localhost:8080/)
## 启动测试
`cd test && npm run testDev`
访问 [http://localhost:8080/test/index.html](http://localhost:8080/test/index.html)
## 打包
`npm run build`
等待进程结束,在`released`里会出现`index.html``output.js``output.module.js`
`index.html`可以直接作为web皮肤
`output.js`为umd模块,可在html中直接使用
`output.module.js`为esm模块,可在react、vue等工程里import使用
比如:
```jsx
import React, { Component } from 'react';
import { Game } from "./output.module";
import './GamePage.less';
export default class GamePage extends Component {
div = null;
game = null;
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
const canvas = document.createElement("canvas");
canvas.style = "width:100%;height:100%";
this.div.appendChild(canvas);
this.game = new Game(canvas);
this.game.initWebEvent();
}
componentWillUnmount() {
this.game.destroy()
}
render() {
return <div
className="game-page"
ref={(div) => this.div = div}
/>;
}
}
```
......@@ -18,6 +18,8 @@
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="//res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge_2.0.44_fixed_HMS.js" crossorigin="anonymous"></script>
<script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script>
<!-- 华夏银行app文件 -->
<script src="//yun.duiba.com.cn/polaris/hxbExtLib.min.f2e3022c5ce5dd92689bff0a5b6c5cb0e9193cd1.js"></script>
......
export * from "./output.module";
// export * from "../../Game/debug/output.module"
var e;!function(e){let t,s,n={},i={},r={},a={},o={},h={};function l(e){if(a[e])return new Promise((e=>{e()}));if(o[e])return o[e];let t=function(e){var t=g(e);if(!t)return null;if(t.atlas){var s=[e+".json"];return t.keys&&(s=s.concat(t.keys.split(",").filter((e=>".png"!=e.substr(-4))))),s}return t.keys?t.keys.split(","):null}(e);if(!t||!t.length)return a[e]=!0,new Promise((e=>{e()}));let s=new Promise(((s,n)=>{!function(e,t){let s=0,n=t.length;n||e(!0);let i=!0;for(var r=0;r<n;r++){d(t[r],((t,r)=>{t||(i=!1),++s==n&&e(i)}),this)}}((t=>{delete o[e],t?(a[e]=!0,s()):n()}),t)}));return o[e]=s,s}function d(t,s,r){var a=t.substring(t.lastIndexOf(".")+1,t.length);if("png"==a||"jpg"==a){let i=n[t]||FYGE.TextureCache[t];if(i)return s&&s.call(r,i,t),new Promise((e=>{e(i)}));if(h[t])return p(t,s,r);if((E=u(t))&&"jpg"!=a){var o=g(E);if(o&&o.atlas){var l=E+".json";return h[l]?h[l].then((e=>{let i=n[t]||FYGE.TextureCache[t];return s&&s.call(r,i,t),i}),(()=>(s&&s.call(r,null,t),null))):d(l).then((()=>{let e=n[t]||FYGE.TextureCache[t];return s&&s.call(r,e,t),e}),(()=>(s&&s.call(r,null,t),null)))}}var c=E?e.resPath+E+"/"+t:t,m=new Promise(((e,i)=>{FYGE.GlobalLoader.loadImage(((a,o)=>{if(delete h[t],a){let i=FYGE.Texture.from(o);n[t]=i,FYGE.Texture.addToCache(i,t),s&&s.call(r,i,t),e(i)}else s&&s.call(r,null,t),i()}),c)}));return h[t]=m,m}if("svga"==a){if(i[t])return s&&s.call(r,i[t],t),new Promise((e=>{e(i[t])}));if(h[t])return p(t,s,r);c=(E=u(t))?e.resPath+E+"/"+t:t,m=new Promise(((e,n)=>{SvgaParser.loadSvga(c,(n=>{delete h[t],i[t]=n,s&&s.call(r,n,t),e(n)}),(e=>{delete h[t],s&&s.call(r,null,t),n(e)}))}));return h[t]=m,m}if("json"==a){if(h[t])return p(t,s,r);var E;c=(E=u(t))?e.resPath+E+"/"+t:t,m=new Promise(((e,i)=>{var a=g(E).atlas;FYGE.GlobalLoader.loadImage(((o,l)=>{if(o){var d=FYGE.createTextureSheet(new FYGE.BaseTexture(l),a);for(let e in d)n[e]=d[e];s&&s.call(r,d,t),e(d)}else delete h[t],s&&s.call(r,null,t),i()}),c.replace("json","png"))}));return h[t]=m,m}}function c(e){if(!e)return null;var t=e.substring(e.lastIndexOf(".")+1,e.length);return"png"==t||"jpg"==t?n[e]||FYGE.TextureCache[e]||null:"svga"==t?i[e]||null:"mp3"==t?r[e]||null:void 0}function u(e){for(var s=0;s<t.groups.length;s++){var n=t.groups[s],i=n.keys;if(i&&i.split(",").indexOf(e)>-1)return n.name;if(n.atlas&&n.name+".json"==e)return n.name}return null}function g(e){for(var s,n=t.groups,i=0;i<n.length;i++)if(n[i].name===e){s=n[i];break}return s}function p(e,t,s){return h[e].then((n=>{t&&t.call(s,n,e)}),(()=>{t&&t.call(s,null,e)})),h[e]}function m(e,t=s){if(!t||!t.children||!t.children.length)return null;for(var n=0;n<t.children.length;n++){var i=t.children[n];if(i.name==e&&("container"==i.type||"item"==i.type))return i;var r=m(e,i);if(r)return r}return null}function E(e){var t;switch(e.type){case"container":t=new FYGE.Container;break;case"button":t=new FYGE.Button(c(e.props.tUp),e.props.tDown?c(e.props.tDown):null,e.props.tDisable?c(e.props.tDisable):null);break;case"text":t=new FYGE.TextField;for(let s in e.props)t[s]=e.props[s];break;case"sprite":t=new FYGE.Sprite(c(e.props.source));break;case"rect":(t=new FYGE.Shape).beginFill(FYGE.string2hex(e.props.fillColor)),t.drawRect(0,0,e.props.width,e.props.height),t.endFill()}return t.name=e.name,t.alpha=e.alpha||1,t.position.set(e.x,e.y),t}e.loadConfig=function(s){t=s,e.resPath=s.path},e.loadGroup=l,e.getResAsync=d,e.getResByUrl=function(){},e.getRes=c,e.loadAllGroup=function(){var e=t.groups,s=[];return e.forEach((e=>{s.push(l(e.name))})),Promise.all(s)},e.loadAllGroupForProgress=function(){return new Promise((e=>{var s=t.groups;let n=0;s.forEach((async t=>{await l(t.name),n++,ae.dispatchEvent("loadPer",n/(s.length-1)),n==s.length-1&&e(0)}))}))},e.loadSkinConfig=function(e){s=e},e.initSkinDisplay=function e(t,s,n){var i="string"==typeof s?m(s):s;if(i.children&&i.children.length)for(var r=0;r<i.children.length;r++){var a=i.children[r];if("item"!=a.type){var o=t.addChild(E(a));n&&a.id&&(n[a.id]=o),"container"==a.type&&e(o,a,n)}}},e.getSkinDataByName=m,e.destroyGroup=function(e){var t=g(e);if(t){var s=[];t.keys&&(s=t.keys.split(","));for(var i=[],r=0;r<s.length;r++){var a=c(s[r]);a&&(-1==i.indexOf(a.baseTexture)&&(a.baseTexture.destroy(),i.push(a.baseTexture)),a.destroy()),delete n[s[r]]}}}}(e||(e={}));let t,s,n=!1;const i=e=>{(()=>{if(!n){n=!0;const o=new a;s=v.topLayer,t=o;var e=(v.stageWidth-160)/2,i=(v.stageHeight-t.height)/2;t.x=v.stageOffsetX-s.x+e,t.y=v.stageOffsetY-s.y+i;var r=(new FYGE.Graphics).beginFill(0).drawRect(-e,-i,v.stageWidth,v.stageHeight).endFill();r.alpha=0,t.addChildAt(r,0)}})(),t.show(e),s.addChild(t)},r=()=>{s.removeChild(t)};class a extends FYGE.Container{msg;constructor(){super();var t=e.getRes("waitingBg.png"),s=new FYGE.Sprite(t);this.addChild(s);var n=e.getRes("waitingRot.png");let i=new FYGE.Sprite(n);i.x=(t.width-n.width)/2,i.y=47,i.anchorX=n.width/2,i.anchorY=n.height/2,this.addChild(i);let r=0;i.addEventListener(FYGE.Event.ENTER_FRAME,(()=>{r++,r%30==0&&(i.rotation+=45)}),this),this.msg=new FYGE.TextField,this.msg.y=125,this.msg.textWidth=t.width,this.msg.textAlign=FYGE.TEXT_ALIGN.CENTER,this.msg.size=26,this.msg.fillColor="#ffffff",this.addChild(this.msg)}show(e="加载中"){this.msg.text=e}destroy(){super.destroy(),this.msg=null}}let o,h,l,d,c=!1;const u=e=>{(()=>{if(!c){c=!0,o=new g,h=v.toastLayer,o.alpha=0,o.x=v.stageOffsetX-h.x+(v.stageWidth-o.width)/2;var e=o.height,t=v.stageOffsetY-h.y;l=t-e,d=t+(v.stageHeight-e)/2}})(),o.show(e),h.addChild(o),FYGE.Tween.removeTweens(o),FYGE.Tween.get(o).set({y:l,alpha:1}).to({y:d},500,FYGE.Ease.quartOut).wait(800).to({alpha:0},300).call((()=>{h.removeChild(o)}))};class g extends FYGE.Container{msg;bg;PADDING=40;constructor(){super(),this.mouseChildren=!1,this.mouseEnable=!1;var t=e.getRes("toastBg.png");this.bg=new FYGE.Sprite(t),this.addChild(this.bg),this.msg=new FYGE.TextField,this.msg.size=28,this.msg.fillColor="0xffffff",this.msg.text="",this.msg.verticalAlign=FYGE.VERTICAL_ALIGN.MIDDLE,this.msg.textHeight=t.height,this.msg.textAlign=FYGE.TEXT_ALIGN.CENTER,this.addChild(this.msg)}show(e){this.msg.text=e,this.msg.x=(this.bg.width-this.msg.textWidth)/2}destroy(){FYGE.Tween.removeTweens(this),super.destroy(),this.msg=null,this.bg=null}}class p{_parent;_bg;stacks=[];static _instance;static get instance(){return p._instance||(p._instance=new p)}init(e){this._parent=e;let t=new FYGE.Shape;t.beginFill(0),t.drawRect(v.stageOffsetX-e.x,v.stageOffsetY-e.y,v.stageWidth,v.stageHeight),t.endFill(),t.hitTestByPixel=!1,t.visible=!1,this._parent.addChild(t),this._bg=t}closeAll(){this.stacks.forEach((e=>e.hidePanel()))}show(e,t){i();const s=new e(t);return this.add(s),this.stacks.push(s),s.onLoaded=()=>{s.y=-(1624-v.stageHeight>>1),r(),this.updateView(!1),s.start(t),s.visible&&s.showAni()},s.onLoadError=()=>{r(),u("资源加载失败"),s.removeEventListener("onDestroy",this.onPanelHide,this),this.remove(s)},s}bgAni;updateView(e=!0){this.stacks.length?(this._parent.visible=!0,"hide"==this.bgAni&&(this.bgAni="show",FYGE.Tween.removeTweens(this._bg),this._bg.alpha=.7),!1===this._bg.visible&&(this._bg.visible=!0,this._bg.alpha=0,FYGE.Tween.get(this._bg).to({alpha:.7},200,FYGE.Ease.cubicOut))):this._bg.visible&&(this.bgAni="hide",FYGE.Tween.removeTweens(this._bg),FYGE.Tween.get(this._bg).to({alpha:0},200,FYGE.Ease.cubicOut).call((()=>{this._bg.visible=!1,this._current=null,this._parent.visible=!1})));for(let t=0;t<this.stacks.length;t++)t<this.stacks.length-1?this.stacks[t].visible=!1:(this.stacks[t].visible=!0,e&&this.stacks[t].showAni(),this._current=this.stacks[t])}add(e){this._parent.addChild(e),e.addEventListener("onDestroy",this.onPanelHide,this)}remove(e){this._parent.removeChild(e),this.stacks=this.stacks.filter((t=>t!=e))}onPanelHide(e){const t=e.target;t.removeEventListener("onDestroy",this.onPanelHide,this),this.remove(t),this.updateView()}_current;get currentPanel(){return this._current}closeCurrent(){this._current&&this._current.hidePanel()}destroy(){p._instance=null,this.stacks=null,this._current=null,this._parent=null,FYGE.Tween.removeTweens(this._bg),this._bg=null}}class m{_parent;_currentScene;static _instance;static get instance(){return m._instance||(m._instance=new m)}init(e){this._parent=e}change(e,t){let s=new e(t);s.visible=!1,i();let n=this._currentScene;s.onLoaded=()=>{r(),s.showAni((()=>{n&&n.destroy()})),s.visible=!0,s.start(t)},s.onLoadError=()=>{r(),u("资源加载失败"),this._currentScene=n||null,this._parent.removeChild(s)},this._currentScene=s,this._parent.addChild(s)}get currentScene(){return this._currentScene}destroy(){m._instance=null,this._currentScene=null,this._parent=null}}class E extends FYGE.Container{_bottomLayer;_sceneLayer;_popupLayer;_toastLayer;_topLayer;_shareLayer;init(e){e.addChild(this);const t=["_bottomLayer","_sceneLayer","_popupLayer","_toastLayer","_topLayer","_shareLayer"];for(let e=0;e<t.length;e++)this[t[e]]=new FYGE.Container,this.addChild(this[t[e]]);this.shareLayer.y=-this.stageOffsetY,m.instance.init(this.sceneLayer),p.instance.init(this.popupLayer)}get bottomLayer(){return this._bottomLayer}get sceneLayer(){return this._sceneLayer}get popupLayer(){return this._popupLayer}get toastLayer(){return this._toastLayer}get topLayer(){return this._topLayer}get shareLayer(){return this._shareLayer}get stageHeight(){return this.stage?this.stage.viewRect.height:0}get stageWidth(){return this.stage?this.stage.viewRect.width:0}get stageOffsetX(){return this.stage?this.stage.viewRect.x:0}get stageOffsetY(){return this.stage?this.stage.viewRect.y:0}}const v=new E;function f(){return m.instance.currentScene}function w(e,t=!0){e&&(FYGE.Tween.removeTweens(e),t&&e.children&&e.children.length&&e.children.forEach((e=>{w(e)})))}function y(){c&&o&&!o.destroyed&&(o.destroy(),o=null,h=null,c=!1),n&&t&&!t.destroyed&&(t.destroy(),t=null,s=null,n=!1),p.instance.destroy(),m.instance.destroy()}class _ extends FYGE.Container{data;constructor(e){super(),this.data=e,this.init()}init(){this.preLoadRes().then((()=>{this.skinName&&e.initSkinDisplay(this,this.skinName,this),this.initUi(),this.onLoaded&&this.onLoaded()}),(()=>{this.onLoadError&&this.onLoadError()}))}preLoadRes(){return new Promise(((t,s)=>{if(this.groupNames&&this.groupNames.length){for(var n=[],i=0;i<this.groupNames.length;i++)n.push(e.loadGroup(this.groupNames[i]));Promise.all(n).then(t,s)}else t()}))}initUi(){}onLoaded;onLoadError;get groupNames(){return null}get skinName(){return null}start(e){this.initEvents()}initEvents(){}removeEvents(){}enableMouseEvt(e){this.mouseEnable=e,this.mouseChildren=e}btnDelay(e,t=2e3){e.mouseEnable=!1,e.mouseChildren=!1,setTimeout((()=>{e.mouseEnable=!0,e.mouseChildren=!0}),t)}destroy(){w(this),this.removeEvents(),this.dispatchEvent("onDestroy"),super.destroy()}}class G extends _{showAni(e){e()}updateScene(){}}class b{autoStart;startTime=0;oldTime=0;elapsedTime=0;running=!1;constructor(e=!0){this.autoStart=e}start(){this.startTime=("undefined"==typeof performance?Date:performance).now(),this.oldTime=this.startTime,this.elapsedTime=0,this.running=!0}stop(){this.getElapsedTime(),this.running=!1,this.autoStart=!1}getElapsedTime(){return this.getDelta(),this.elapsedTime}getDelta(){let e=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){const t=("undefined"==typeof performance?Date:performance).now();e=(t-this.oldTime)/1e3,this.oldTime=t,this.elapsedTime+=e}return e}}const C={dropSpeed:650,interval:.15,player:"人物.png",rainObj:["金币.png","红包1.png","红包2.png","红包3.png","fudai.png"]};function x(e){for(let t in e)C[t]=e[t]}var F=FYGE.Container,T=FYGE.Button,L=FYGE.MouseEvent,Y=FYGE.Sprite,A=FYGE.TEXT_ALIGN,R=FYGE.TextField,S=FYGE.Shape,D=FYGE.Lottie,j=FYGE.Texture,O=FYGE.Graphics,k=FYGE.BitmapText;class P{static Btn(t,s,n,i,r=0,a=0,o,h,l=s,d=s){const c=new T(e.getRes(s),e.getRes(l),e.getRes(d));return c.addEventListener(L.CLICK,n,i),c.position.set(r,a),void 0!==o&&(c.anchorX=o),void 0!==h&&(c.anchorY=h),t&&t.addChild(c),c}static Sp(t,s,n=0,i=0){let r;if(s instanceof j)r=new Y(s);else{const t=e.getRes(s);r=t?new Y(t):Y.fromUrl(s)}return r.position.set(n,i),t&&t.addChild(r),r}static Ctn(e,t=0,s=0){const n=new F;return n.position.set(t,s),n&&e.addChild(n),n}static Txt(e,t,s,n="#000000",i=A.LEFT,r=0,a=0,o=0,h=!1){const l=new R;return l.fillColor=n,l.size=s,r&&(l.textWidth=r),l.textAlign=i,l.position.set(a,o),l.text=t,l.bold=h,e&&e.addChild(l),l}static Rect(e,t,s,n=16711680,i=0,r=0,a=0,o=1){const h=new S;return h.beginFill(n),i?h.drawRoundedRect(0,0,t,s,i):h.drawRect(0,0,t,s),h.endFill(),h.alpha=o,h.position.set(r,a),e&&e.addChild(h),h}static Lottie(e,t,s=0,n=0){const i=new D(t);return i.x=s,i.y=n,e&&e.addChild(i),i}static Shape(e,t=0,s=0){const n=new S;return n.position.set(t,s),e&&e.addChild(n),n}static Graphics(e,t=0,s=0){const n=new O;return n.position.set(t,s),e&&e.addChild(n),n}static BitTxt(e,t,s="",n=0,i=0,r=1,a=1,o=0){const h=new k(t);return h.position.set(n,i),h.scale.set(r,a),h.text=s,h.gap=o,e&&e.addChild(h),h}}var N=FYGE.Container,I=FYGE.MouseEvent;class B extends N{static _pool=[];static get(){return this._pool.splice(0,1)[0]||new B}static put(e){return this._pool.push(e)}image=null;constructor(){super(),this.init()}reset(){const{width:e,height:t}=this.image,s=e/2+Math.random()*(750-e);this.position.set(s,200*-Math.random()-t),this.rotation=50*Math.random()+10}init(){const e=C.rainObj[Math.random()*C.rainObj.length>>0];this.name=e,this.image=P.Sp(this,e),this.image.anchorTexture.set(.5,.5),this.addEventListener(I.MOUSE_DOWN,(e=>{f().removeObj(this),f().addEffect(this.x,this.y,this.name),ae.dispatchEvent(ie.ADD_SCORE,{type:"redBag"})}))}}var M,H=FYGE.Event,W=FYGE.SvgaAni;class q extends G{get groupNames(){return["game"]}clock=new b;isPause=!0;eTime=0;objList=[];objCtn;effectCtn;initUi(){this.objCtn=P.Ctn(this),this.effectCtn=P.Ctn(this),this.effectCtn.mouseEnable=this.effectCtn.mouseChildren=!1}async start(e){super.start(e),ae.dispatchEvent(ie.READY)}addEffect(t,s,n){const i={"红包1.png":"点中红包飘爱心.svga","红包2.png":"点中飘金币.svga","红包3.png":"点中红包飘爱心.svga","金币.png":"点中飘金币.svga","fudai.png":"点中红包飘爱心.svga"}[n]||"点中红包飘爱心.svga",r=this.effectCtn.addChild(new W(e.getRes(i))),{videoWidth:a,videoHeight:o,totalFrames:h}=r;r.position.set(t-a/2,s-o/2),r.startAniRange(0,h,1,(()=>{this.effectCtn.removeChild(r)}))}addObj(){const e=B.get();e.reset(),this.objCtn.addChild(e),this.objList.push(e)}removeObj(e){this.objList.splice(this.objList.indexOf(e),1),this.objCtn.removeChild(e),B.put(e)}initEvents(){super.initEvents(),ae.addEventListener(ie.START_GAME,this.startGame,this),ae.addEventListener(ie.END_GAME,this.endGame,this),this.addEventListener(H.ENTER_FRAME,this.onUpdate,this)}removeEvents(){super.removeEvents(),ae.removeEventListener(ie.START_GAME,this.startGame,this),ae.removeEventListener(ie.END_GAME,this.endGame,this),this.removeEventListener(H.ENTER_FRAME,this.onUpdate,this)}startGame(){if(!this.isPause)return console.warn("已经开始了");this.isPause=!1,this.eTime=0}endGame(){if(this.isPause)return console.warn("已经结束了");this.objList.forEach((e=>{this.removeObj(e)})),this.objList.length=0,this.objCtn.removeAllChildren(),this.isPause=!0}onUpdate(){if(this.isPause)return;const{interval:e,dropSpeed:t}=C,{objList:s,clock:n}=this;let i=n.getDelta();i>.067&&(i=.067),this.eTime+=i,this.eTime>e&&(this.eTime=e-this.eTime,this.addObj());for(let e=s.length-1;e>=0;e--){const n=s[e];n.y+=t*i,n.y>1724&&this.removeObj(n)}}}!function(e){e.index="/projectx/{projectId}/game/index.do",e.join="/projectx/{projectId}/game/join.do",e.queryResult="/projectx/{projectId}/game/queryResult.do",e.projectRule="/projectx/{projectId}/projectRule.query"}(M||(M={}));var U,X,V=location.href.indexOf(".com.cn/projectx")>=0;!function(e){if(V){var t=document.getElementsByTagName("head")[0];const s=document.createElement("script");s.src="getTokenKey?_="+Date.now(),s.onload=function(){t.removeChild(s),e&&e(!0)},s.onerror=function(){t.removeChild(s),e&&e(!1)},t.appendChild(s)}else e&&e(!0)}(),function(e){e.EXPOSURE="exposure",e.CLICK="click"}(U||(U={})),function(e){e.getAppData="mine.getAppData",e.getVoiceType="mine.getVoiceType"}(X||(X={}));const z=window.my;"web"==FYGE.getEnv()&&z&&(z.onMessage=function(e){console.log("返回数据",e.netName,e.data),ae.dispatchEvent(e.netName,e.data)});const K={groups:[{keys:"comCloseBtn.png,toastBg.png,waitingBg.png,waitingRot.png",name:"common",atlas:{"waitingBg.png":{x:2,y:134,w:160,h:180,ox:0,oy:0,sw:160,sh:180,ro:!0},"toastBg.png":{x:2,y:2,w:460,h:130,ox:0,oy:0,sw:460,sh:130,ro:!1},"waitingRot.png":{x:184,y:194,w:56,h:56,ox:0,oy:0,sw:56,sh:56,ro:!1},"comCloseBtn.png":{x:184,y:134,w:58,h:58,ox:0,oy:0,sw:58,sh:58,ro:!1}}},{keys:"coin.svga,fudai.png,点中红包飘爱心.svga,点中飘金币.svga,红包1.png,红包2.png,红包3.png,金币.png",name:"game",atlas:{"红包1.png":{x:311,y:152,w:105,h:134,ox:0,oy:0,sw:105,sh:134,ro:!0},"fudai.png":{x:311,y:2,w:148,h:148,ox:0,oy:0,sw:148,sh:148,ro:!1},"红包2.png":{x:2,y:234,w:177,h:150,ox:0,oy:0,sw:177,sh:150,ro:!1},"金币.png":{x:181,y:259,w:99,h:75,ox:0,oy:0,sw:99,sh:75,ro:!0},"红包3.png":{x:2,y:2,w:307,h:230,ox:0,oy:0,sw:307,sh:230,ro:!1}}}],path:"https://yun.duiba.com.cn/db_games/activity/template/1706532299/resource/"},$={x:0,y:0,type:"container",children:[]},J=async(t="common")=>{e.loadConfig(K),console.log("初始化资源配置完成"),e.loadSkinConfig($),console.log("初始化皮肤配置完成"),"string"==typeof t?await e.loadGroup(t):Array.isArray(t)&&await Promise.all(t.map((t=>e.loadGroup(t)))),console.log(`资源组${t}加载完成`)};var Q=FYGE.Tween,Z=FYGE.Stage,ee=FYGE.RENDERER_TYPE,te=FYGE.Event,se=FYGE.getEnv;class ne{stage;requestID;_pause;canvas;constructor(e,t=750,s=1624,n,i,r=ee.WEBGL,a=!0,o=!1,h){let l;window||(FYGE.initedByCanvas(e),l=my.getSystemInfoSync()),n=n||l?.windowWidth||document.body.clientWidth,i=i||l?.windowHeight||document.body.clientHeight,h=h||l?.pixelRatio||window.devicePixelRatio||1;const d=this.stage=new Z(e,t,s,n,i,r,a,o,h);this.canvas=e,d.addEventListener(te.INIT_STAGE,this.onAddToStage,this),this.loop()}loop=()=>{this._pause||(Q.flush(),this.stage.flush()),"tb"==se()?this.requestID=this.canvas.requestAnimationFrame(this.loop):this.requestID=window.requestAnimationFrame(this.loop)};async onAddToStage(){var e,t;v.init(this.stage),console.log("初始化层级完成"),await J("common"),"web"==se()&&document.getElementById("__loading__")&&(document.getElementById("__loading__").style.display="none"),e=q,m.instance.change(e,t)}initWebEvent(){const e=this.stage.onMouseEvent.bind(this.stage);this.canvas.addEventListener("touchstart",e,!1),this.canvas.addEventListener("touchmove",e,!1),this.canvas.addEventListener("touchend",e,!1)}run(){this._pause=!1,Q._lastTime=null,ae.dispatchEvent({type:ie.ON_SHOW})}pause(){ae.dispatchEvent({type:ie.ON_HIDE})}destroy(){Q.removeAllTweens(),"tb"==FYGE.getEnv()?this.canvas.cancelAnimationFrame(this.requestID):window.cancelAnimationFrame(this.requestID),v.removeChildren(),v.parent&&v.parent.removeChild(v),y(),this.stage.destroy(),ae.removeAllEventListener()}}var ie,re=FYGE.EventDispatcher;!function(e){e.READY="READY",e.START_GAME="START_GAME",e.END_GAME="END_GAME",e.ADD_SCORE="ADD_SCORE",e.ON_SHOW="ON_SHOW",e.ON_HIDE="ON_HIDE"}(ie||(ie={}));const ae=new re;export{ie as GAME_EVENT,ae as GDispatcher,ne as Game,J as preloadRes,x as setConfig};
//# sourceMappingURL=output.module.js.map
......@@ -64,6 +64,7 @@ class DetailPage extends React.Component<any, any> {
yesterdayProfit: data.yesterdayProfit,
availableFunds: data.availableFunds,
minBuyLimit: data.minBuyLimit,
sellInput: data.availableFunds,
});
}
......
......@@ -15,6 +15,7 @@ import ResPage from '../ResPage/ResPage';
import Countdown from '@/core/components/ComCountdown/index.jsx';
import ProductListPage from '../productListPage/productListPage';
import PrizePage from "@/pages/PrizePage/PrizePage.tsx";
import RedPackRainModal from '@/panels/redPackRainModal/redPackRainModal';
@observer
class HomePage extends React.Component<any, any> {
......@@ -28,6 +29,8 @@ class HomePage extends React.Component<any, any> {
async componentDidMount() {
await store.judgeIsWhiteUser();
// ModalCtrl.showModal(RedPackRainModal)
}
/** 跳转模拟交易记录 */
......
@import '../../res.less';
.redPackRainModal {
width: 100%;
height: 100%;
position: absolute;
.gameCutDownBg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
// background-color: rgba(0, 0, 0, 0.7);
overflow: hidden;
.cutDownSvga {
width: 677px;
height: 947px;
position: absolute;
left: 36px;
top: 200px;
}
}
.cd {
position: absolute;
left: 273px;
//top: 196px;
top: 12.0%;
width: 203px;
height: 136px;
.webpBg("homePage/cdBg.png");
.cd-text {
position: absolute;
left: 50px;
top: 43px;
width: 108px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
font-size: 48.47px;
color: #ff0000;
font-weight: bold;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import { Game, GAME_EVENT, GDispatcher } from "../../GameModule/GameModule";
import './redPackRainModal.less';
import store from '@/store/store';
import { _throttle } from '@/utils/utils';
class RedPackRainModal extends Component<any, any> {
state = {
// 红包雨时间
gameDuration: store?.rpStartInfo?.durationSeconds,
// 是否准备
showReady: true,
}
async componentDidMount() {
await this.initGame()
// GDispatcher.dispatchEvent(GAME_EVENT.START_GAME);
// this.startTimer();
}
onEnd = () => {
this.setState({ showReady: false}, () => {
// modalStore.pushPop("RedPackRainModal")
GDispatcher.dispatchEvent(GAME_EVENT.START_GAME);
this.startTimer();
});
}
playground = null;
game = null;
awaitInitGame = null;
/** 初始化游戏舞台 */
initGame() {
if (!this.awaitInitGame) {
this.awaitInitGame = new Promise((resolve: any) => {
const canvas:any = document.createElement("canvas");
canvas.style = "position:absolute;width:100%;height:100%";
this.playground.appendChild(canvas);
this.game = new Game(canvas, 750, 1624);
this.game.initWebEvent();
GDispatcher.once(GAME_EVENT.READY, () => {
resolve();
});
GDispatcher.addEventListener(GAME_EVENT.ADD_SCORE, this.clickRed, this);
});
}
return this.awaitInitGame;
}
score = 0;
clickRed = _throttle(() => {
this.score += 1;
}, 0);
timer = null;
startTimer = () => {
let { gameDuration } = this.state;
this.timer = setInterval(async () => {
if (gameDuration <= 0) {
this.gameStop();
} else {
this.setState({
gameDuration: (gameDuration -= 1)
});
}
}, 1000);
}
gameStop = async () => {
// this.gameIng = false;
GDispatcher.dispatchEvent(GAME_EVENT.END_GAME);
clearInterval(this.timer);
// return
// const { success, data } = await API.rpRainSubmit({
// period: kmhStore.kmhInfo?.triggerRpRainPeriod,
// recordId: store.rpStartInfo?.recordId
// }) || {};
// if (success && (data?.prize?.prizeType != 0)) {
// modalStore.pushPop("GetPrizeModal", { ...data?.prize});
// } else {
// modalStore.pushPop("NoPrizeModal");
// }
// await kmhStore.getKMHIndex();
// modalStore.closePop("RedPackRainModal")
}
componentWillUnmount() {
clearInterval(this.timer);
GDispatcher.removeEventListener(GAME_EVENT.ADD_SCORE, this.clickRed, this);
this.setState = () => 0;
}
render() {
const {gameDuration, showReady} = this.state;
return (
<div className='redPackRainModal'>
<div className="game_canvas" ref={(playground) => (this.playground = playground)}></div>
<div className="cd">
<div className="cd-bg"/>
<div className="cd-text">{gameDuration}s</div>
</div>
</div>
);
}
}
export default RedPackRainModal;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment