From e5ccf21cb344dcdfbf1df964255479a5ca25afd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=9D=E7=88=B7?= Date: Mon, 20 Sep 2021 23:51:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Esetter=E9=80=89=E9=A1=B9?= =?UTF-8?q?=EF=BC=8C=E5=BA=94=E5=AF=B9=E7=89=B9=E6=AE=8A=E7=9A=84=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/Script/example/SyncExmaple.ts | 7 ++-- assets/Script/sync/SyncUtil.ts | 50 +++++++++++++++++++--------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/assets/Script/example/SyncExmaple.ts b/assets/Script/example/SyncExmaple.ts index c78ed83..df9353e 100644 --- a/assets/Script/example/SyncExmaple.ts +++ b/assets/Script/example/SyncExmaple.ts @@ -1,5 +1,5 @@ import { Component, Label, _decorator, view, director, Node, RichText, tween, Tween, math, randomRange, Vec3, Quat } from "cc"; -import { applyDiff, getReplicateObject, makeObjectReplicated } from "../sync/SyncUtil"; +import { applyDiff, getReplicateObject, makeObjectReplicated, ReplicatedOption } from "../sync/SyncUtil"; const { ccclass, property } = _decorator; @@ -20,7 +20,10 @@ export default class SyncExample extends Component { // 跟踪的属性并不能直接apply,而是需要调用接收者的如setPosition等方法使其生效 // 这里可以考虑将Node的同步作为一个组件进行挂载,专门负责与Cocos节点相关的同步工作 // 也可以考虑通过装饰器参数的描述来处理这种情况,比如 { name : _lpos, setter : setPosition, } - let syncProperty = ['_lscale', '_lpos', '_euler']; + let syncProperty : ReplicatedOption[] = [ + {Name : '_lscale', Setter: 'setScale'}, + {Name : '_lpos', Setter: 'setPosition'}, + {Name : '_euler', Setter: 'eulerAngles'}]; makeObjectReplicated(this.leftNode, { SyncProperty : syncProperty}); } diff --git a/assets/Script/sync/SyncUtil.ts b/assets/Script/sync/SyncUtil.ts index ec55a4e..b097b54 100644 --- a/assets/Script/sync/SyncUtil.ts +++ b/assets/Script/sync/SyncUtil.ts @@ -13,16 +13,26 @@ export type ReplicateNotify = (target: any, key: string, value: any) => boolean; * 属性同步选项 */ export interface ReplicatedOption { - /** 指定同步哪些属性 */ - SyncProperty?: string[]; - /** 指定跳过哪些属性的同步 */ - SkipProperty?: string[]; + /** 要同步的属性名 */ + Name: string; + /** 应用同步的方法,默认为Name */ + Setter?: string; /** 属性同步条件 */ Condiction?: number; /** 同步回调 */ Notify?: ReplicateNotify; } +/** + * 对象属性同步配置 + */ +export interface ObjectReplicatedOption { + /** 指定同步哪些属性 */ + SyncProperty?: ReplicatedOption[]; + /** 指定跳过哪些属性的同步 */ + SkipProperty?: string[]; +} + export const REPLICATE_OBJECT_INDEX = "__repObj__"; /** @@ -34,7 +44,7 @@ export const REPLICATE_OBJECT_INDEX = "__repObj__"; export function getReplicateObject(target: any, autoCreator: boolean = false): ReplicateObject { let ret: ReplicateObject = target[REPLICATE_OBJECT_INDEX]; if (!ret && autoCreator) { - ret = new ReplicateObject(); + ret = new ReplicateObject(); target[REPLICATE_OBJECT_INDEX] = ret; } return ret; @@ -47,20 +57,26 @@ export function getReplicateObject(target: any, autoCreator: boolean = false): R * @param descriptor 属性的描述符 * @param option 自定义同步选项 */ -export function makePropertyReplicated(target: any, propertyKey: string, descriptor?: PropertyDescriptor, option?:ReplicatedOption) { +export function makePropertyReplicated(target: any, propertyKey: string, descriptor?: PropertyDescriptor, option?: ReplicatedOption) { if (!descriptor) { descriptor = Object.getOwnPropertyDescriptor(target, propertyKey); } if (descriptor) { // 在不影响原来set方法的基础上自动跟踪属性变化 let oldValue = descriptor.value; + let realProperty: string; + if (option && option.Setter) { + realProperty = option.Setter; + } else { + realProperty = propertyKey; + } delete descriptor.value; delete descriptor.writable; let oldSet = descriptor.set; descriptor.set = (v: any) => { let repObj = getReplicateObject(target, true); // 标记属性发生变化 - repObj.propertyChanged(propertyKey, v); + repObj.propertyChanged(realProperty, v); if (oldSet) { oldSet(v); } @@ -70,7 +86,7 @@ export function makePropertyReplicated(target: any, propertyKey: string, descrip if (!oldGet) { descriptor.get = () => { let repObj = getReplicateObject(target, true); - return repObj.getProperty(propertyKey); + return repObj.getProperty(realProperty); } } Object.defineProperty(target, propertyKey, descriptor); @@ -86,21 +102,21 @@ export function makePropertyReplicated(target: any, propertyKey: string, descrip * @param target * @param option */ -export function makeObjectReplicated(target: any, option?:ReplicatedOption) { +export function makeObjectReplicated(target: any, option?: ObjectReplicatedOption) { if (option && option.SyncProperty) { - option.SyncProperty.forEach((key) => { - let descriptor = Object.getOwnPropertyDescriptor(target, key); + option.SyncProperty.forEach((pOpt) => { + let descriptor = Object.getOwnPropertyDescriptor(target, pOpt.Name); if (descriptor) { - makePropertyReplicated(target, key, descriptor, option); + makePropertyReplicated(target, pOpt.Name, descriptor, pOpt); } }); } else { let keys = Object.keys(target); keys.forEach((key) => { if (!(option?.SkipProperty && option.SkipProperty.indexOf(key) >= 0)) { - makePropertyReplicated(target, key, Object.getOwnPropertyDescriptor(target, key), option); + makePropertyReplicated(target, key, Object.getOwnPropertyDescriptor(target, key)); } - }) + }) } } @@ -109,10 +125,12 @@ export function makeObjectReplicated(target: any, option?:ReplicatedOption) { * @param diff * @param target */ -export function applyDiff(diff : any, target : any) { +export function applyDiff(diff: any, target: any) { let keys = Object.keys(diff); keys.forEach((propertyName) => { - if(diff[propertyName] instanceof Object) { + if (typeof target[propertyName] == "function") { + target[propertyName](diff[propertyName]); + } else if (diff[propertyName] instanceof Object) { if (target[propertyName] instanceof Object) { let prop = target[propertyName]; applyDiff(diff[propertyName], prop);