csharp DLX_DisableApprVendExpired

禁用已批准的供应商。 <br/>从批处理中删除最后一个值?

DLX_DisableApprVendExpiredDC
// DLX_SCMBUG3533_VendorIFControls - 20171018 - Mirco Z
[
    DataContractAttribute
]
class DLX_DisableApprVendExpiredDC
{
    str packedQuery;
}

public Query getQuery()
{
    return new Query(SysOperationHelper::base64Decode(packedQuery));
}

[DataMemberAttribute,
    AifQueryTypeAttribute('_packedQuery', querystr(DLX_PdsApprovedVendorList))
]
public str parmQuery(str _packedQuery = packedQuery)
{
    packedQuery = _packedQuery;
    return packedQuery;
}

public void setQuery(Query _query)
{
    packedQuery = SysOperationHelper::base64Encode(_query.pack());
}
DLX_DisableApprVendExpiredController
// DLX_SCMBUG3533_VendorIFControls - 20171018 - Mirco Z
class DLX_DisableApprVendExpiredController extends SysOperationServiceController
{
    DLX_DisableApprVendExpiredDC    disableApprVendExpiredDC;
}

public void initFromCaller(Args _args)
{
    this.initializeFromArgs(_args);
}

public static DLX_DisableApprVendExpiredController construct()
{
    return new DLX_DisableApprVendExpiredController();
}


public static void main(Args args)
{
    DLX_DisableApprVendExpiredController disableApprVendExpiredController = DLX_DisableApprVendExpiredController::construct();
    ;

    disableApprVendExpiredController.initFromCaller(args);

    if(disableApprVendExpiredController)
    {
        xSysLastValue::deleteLast(disableApprVendExpiredController);
        disableApprVendExpiredController.startOperation();
        xSysLastValue::deleteLast(disableApprVendExpiredController);
    }
}
DLX_DisableApprVendExpiredService
// DLX_SCMBUG3533_VendorIFControls - 20171018 - Mirco Z
class DLX_DisableApprVendExpiredService extends SysOperationServiceBase
{
}

[SysEntryPointAttribute(true)]
public void disableApprVendor(DLX_DisableApprVendExpiredDC  _disableApprVendExpiredDC)
{
    DLX_DisableApprVendExpiredMng disableApprVendExpiredMng = DLX_DisableApprVendExpiredMng::construct();
    ;

    if(disableApprVendExpiredMng)
    {
        disableApprVendExpiredMng.parmDisableApprVendExpiredDC(_disableApprVendExpiredDC);
        disableApprVendExpiredMng.run();
    }
}
DLX_DisableApprVendExpiredMng
// DLX_SCMBUG3533_VendorIFControls - 20171018 - Mirco Z
class DLX_DisableApprVendExpiredMng
{
    DLX_DisableApprVendExpiredDC    disableApprVendExpiredDC;
}

public DLX_DisableApprVendExpiredDC parmDisableApprVendExpiredDC(DLX_DisableApprVendExpiredDC _disableApprVendExpiredDC = disableApprVendExpiredDC)
{
    disableApprVendExpiredDC = _disableApprVendExpiredDC;

    return disableApprVendExpiredDC;
}

public void run()
{
    QueryRun                queryRun;
    PdsApprovedVendorList   approvedVendorList;
    ;

    try
    {
        if (this.parmDisableApprVendExpiredDC() )
        {
            queryRun = new QueryRun(disableApprVendExpiredDC.getQuery());

            while (queryRun.next() )
            {
                approvedVendorList = queryRun.get(tableNum(PdsApprovedVendorList));

                if (approvedVendorList.ValidTo      <  systemDateGet()
                    && approvedVendorList.ValidTo   != dateNull() )
                {
                    ttsBegin;
                    approvedVendorList.selectForUpdate(true);

                    approvedVendorList.validTimeStateUpdateMode(ValidTimeStateUpdate::Correction);
                    approvedVendorList.DisableFlag_dlx  = NoYes::Yes;

                    approvedVendorList.update();
                    ttsCommit;

                    info(strFmt("@DLX2821", approvedVendorList.PdsApprovedVendor, approvedVendorList.ItemId));
                }
            }
        }
    }
    catch
    {
        throw error("@SYS70403");
    }
}

public static DLX_DisableApprVendExpiredMng construct()
{
    return new DLX_DisableApprVendExpiredMng();
}

csharp DLX_DeliveryPlanReport

保存报告PDF。通过电子邮件发送报告

DLX_DeliveryPlanReportDC
// DLX_ACQ0026_DeliveryPlanReport - 20161012 - GR_SCA_L120
[DataContractAttribute]
class DLX_DeliveryPlanReportDC
{
    VendAccount         vendAccount;
    Inventsiteid        inventSiteId;                   // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731
    DLX_AlignmentType   alignmentType;
    DLX_ReminderType    reminderType;
    DLX_RecurrenceWeekDays      recurrenceWeekDays;     // DLX_SCM_BUG_2890_BatchVendReminder - Luca Gir8 - 20170609
}

// DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731
[DataMemberAttribute]
public inventSiteId parmInventSiteId(InventSiteId _inventSiteId = inventSiteId)
{
    inventSiteId = _inventSiteId;

    return inventSiteId;
}

[DataMemberAttribute]
public VendAccount parmVendAccount(VendAccount _vendAccount = vendAccount)
{
    vendAccount = _vendAccount;

    return vendAccount;
}
DLX_DeliveryPlanReportController
class DLX_DeliveryPlanReportController extends SrsReportRunController
{
    FilePath                    filePath;
    DLX_DeliveryPlanVendorInfo  deliveryPlanVendorInfo;
    FilePath                    pathPdf;
}

private void createPDF(DLX_DeliveryPlanVendorInfo _deliveryPlanVendorInfo, inventSiteId _inventSiteId)
{

    DLX_DeliveryPlanReportDC        contract    = this.parmReportContract().parmRdpContract() as DLX_DeliveryPlanReportDC;
    //DLX_SCMParametersDim            parameters  = DLX_SCMParametersDim::findBySiteId(_inventSiteId);
    DLX_SCMParameters               parameters  = DLX_SCMParameters::find();
    SRSPrintDestinationSettings     settings;
    str                             labelStr;
    NumberSeq                       numberSeq   = NumberSeq::newGetNum(VendParameters::NumRefFax_dlx());
    str                             currentDate = date2str(DateTimeUtil::date(DateTimeUtil::getSystemDateTime()),
                                                           123,
                                                           DateDay::Digits2,
                                                           DateSeparator::None,
                                                           DateMonth::Digits2,
                                                           DateSeparator::None,
                                                           DateYear::Digits4,
                                                           1);
    #define.Backslash("\\")
    #define.pdf(".pdf")
    #define.doc(".doc");

    /*
    if(contract.parmAlignmentType())
        labelStr = #Alignment;

    if(contract.parmReminderType())
        labelStr = #Reminder;
    */

    if (parameters.DeliveryPlan)
        labelStr = strFmt("%1%2%1%3%1",#Backslash,parameters.DeliveryPlan,_inventSiteId);
    else
        labelStr = '';

    settings =  this.parmReportContract().parmPrintSettings();
    settings.printMediumType(SRSPrintMediumType::File);
    settings.overwriteFile(true);

    settings.fileFormat(SRSReportFileFormat::PDF);
    pathPdf = parameters.DeliveryPlanReportFilePath +
            labelStr +
            _deliveryPlanVendorInfo.vendAccount +
            "_" + VendTable::find(_deliveryPlanVendorInfo.vendAccount).name() + "_" + currentDate + "_" + NumberSeq.num() + #pdf;

    this.parmFilePath(pathPdf);

    settings.fileName(pathPdf);
    this.parmReportContract().parmPrintSettings(settings);
}

private str getDate()
{
        str dd, mm, yy, dt;

    dt = date2Str(systemDateGet(), 123, DateDay::Digits2, DateSeparator::Slash, DateMonth::Digits2,
           DateSeparator::Slash, DateYear::Digits4);

    dd = substr(dt, 0, 2);
    mm = substr(dt, 4, 2);
    yy = substr(dt, 7, 4);

    dt = dd + '/' + mm + '/' + yy;

    return dt;
}

public FilePath parmFilePath(FilePath _filePath = filePath)
{
    filePath = _filePath;
    return filePath;
}

protected void preRunModifyContract()
{
    DLX_DeliveryPlanReportDC    contract;

    contract = this.parmReportContract().parmRdpContract() as DLX_DeliveryPlanReportDC;

    if (this.parmArgs().record() is DLX_DeliveryPlanVendorInfo)
    {
        deliveryPlanVendorInfo = this.parmArgs().record();

        contract.parmVendAccount(deliveryPlanVendorInfo.VendAccount);
        contract.parmInventSiteId(deliveryPlanVendorInfo.InventSiteId);  // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731

    }
}

private void returnToPreview()
{
    SRSPrintDestinationSettings     settings;
    ;

    settings =  this.parmReportContract().parmPrintSettings();
    settings.printMediumType(SRSPrintMediumType::Screen);
    settings.overwriteFile(true);
    this.parmReportContract().parmPrintSettings(settings);
}

public void runReport()
{
    InventSiteId        inventSiteId;
    NoYes               showReport;
    SCM_Fax             faxClass    = new SCM_Fax();
    ;


    deliveryPlanVendorInfo  = this.parmArgs().record();
    showReport              = this.parmArgs().parmEnum();
    // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731 - Begin
    //select firstOnly inventSiteId from deliveryPlan
    //order by runNum desc;

    //inventSiteId = deliveryPlan.InventSiteId;
    inventSiteId           = deliveryPlanVendorInfo.InventSiteId;
    // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731 - End

    if (!showReport)
    {

        if ((deliveryPlanVendorInfo.SendEmail && deliveryPlanVendorInfo.Email != "0") ||
            (deliveryPlanVendorInfo.SendFax && deliveryPlanVendorInfo.Fax != "0"))
        {
            this.createPDF(deliveryPlanVendorInfo, inventSiteId);// vendTable::find(deliveryPlanVendorInfo.VendAccount).InventSiteId);

            if (deliveryPlanVendorInfo.SendEmail)
            {
                this.parmReportContract().parmReportName(ssrsReportStr(DLX_DeliveryPlanReport, Report));
                super();
                this.sendMail(filePath, deliveryPlanVendorInfo.email, inventSiteId);// vendTable::find(deliveryPlanVendorInfo.VendAccount).InventSiteId);
            }

            if (deliveryPlanVendorInfo.SendFax)
            {
                this.parmReportContract().parmReportName(ssrsReportStr(DLX_DeliveryPlanReport, PortraitReport));
                super();
                faxClass.Send(/*vendTable::find(deliveryPlanVendorInfo.VendAccount).InventSiteId,*/ inventSiteId, filePath , deliveryPlanVendorInfo.fax);
            }
        }
    }
    else
    {
        this.parmReportContract().parmReportName(ssrsReportStr(DLX_DeliveryPlanReport, Report));
        this.returnToPreview();
        super();
    }

}

private void sendMail(FilePath _pdfFilePath, Email  _emailTo, InventSiteId _inventSiteId)
{
    str                                     Body = strFmtLB("@DLX1567");
    str                                     Subject = strFmt("@DLX3356", InventSite::find(_inventSiteId).Name, this.getDate()); /*strFmt("@DLX1568", this.getDate());*/ //DLX_SCM_4551_MailSubjectWithSite - 21022018 - MSakollari
    //SysINetMail                             mail = new SysINetMail(); NOT USED // DLX_BUG2196_GoLiveFixesZanin - 20170411 - Mirco Z

    str                                     sender = HcmWorker::find(DLX_SCMParametersDim::findBySiteId(_inventsiteId).DeliveryPlanPlanner).email();
    str                                     mailServer;
    int                                     mailServerPort;
    System.Net.Mail.SmtpClient              mailClient;
    System.Net.Mail.MailMessage             mailMessage;
    System.Net.Mail.MailAddress             mailFrom;
    System.Net.Mail.MailAddress             mailTo;
    System.Net.Mail.MailAddressCollection   mailToCollection;
    System.Net.Mail.AttachmentCollection    mailAttachementCollection;
    System.Net.Mail.Attachment              mailAttachment;
    ;

    try
    {
        //_EmailTo = 'lucianaMilo10@gmail.com';
        //sender = 'dcartella@outlook.it';
        mailServer = SysEmaiLParameters::find(false).SMTPRelayServerName;
        mailServerPort = SysEmaiLParameters::find(false).SMTPPortNumber;
        mailClient = new System.Net.Mail.SmtpClient(mailServer, mailServerPort);

        mailFrom = new System.Net.Mail.MailAddress(sender);
        mailTo  = new System.Net.Mail.MailAddress(_emailTo);
        mailMessage = new System.Net.Mail.MailMessage(mailFrom, mailTo);

        mailToCollection = mailMessage.get_To();
        mailToCollection.Add(_emailTo);

        mailAttachementCollection = mailMessage.get_Attachments();
        mailAttachment = new System.Net.Mail.Attachment(@_pdfFilePath);
        mailAttachementCollection.Add(mailAttachment);

        mailMessage.set_Priority(System.Net.Mail.MailPriority::High);
        mailMessage.set_Subject(Subject);
        mailMessage.set_Body(body);

        mailClient.Send(mailMessage);
        mailMessage.Dispose();

        CodeAccessPermission::revertAssert();

        info(strFmt("@DLX1713", _emailTo));     // DLX_BUG2196_GoLiveFixesZanin - 20170411 - Mirco Z
    }
    catch(Exception::CLRError)
    {
        // Handle the exception and display message in the InfoLog.
       // error(AifUtil::getClrErrorMessage());
        infolog.clear();

    }
}

public SysOperationStartResult startOperation()
{
    SysOperationStartResult ret;

    ret = super();

    return ret;
}

public static void main(Args _args)
{
    DLX_DeliveryPlanReportController deliveryPlanReportController = new DLX_DeliveryPlanReportController();
    ;

    deliveryPlanReportController.parmArgs(_args);
    deliveryPlanReportController.parmReportName(ssrsReportStr(DLX_DeliveryPlanReport, Report));
    deliveryPlanReportController.parmShowDialog(false);

    deliveryPlanReportController.startOperation();

}
DLX_DeliveryPlanReportDP
// DLX_ACQ0026_DeliveryPlanReport - 20161012 - GR_SCA_L120
[
SRSReportParameterAttribute(classstr(DLX_DeliveryPlanReportDC))
]
class DLX_DeliveryPlanReportDP extends
                            SRSReportDataProviderBase
                            //SRSReportDataProviderPreProcess
{
    DLX_DeliveryPlanReportDC            contract;
    VendAccount                         vendAccount;
    DLX_DeliveryPlanReportHeaderTmp     deliveryPlanReportHeaderTmp;
    DLX_DeliveryPlanReportTmp           deliveryPlanTmp;

    DLX_DeliveryPlan                    deliveryPlan;
    Args                                args;
    Qty                                 schedQty, receivedQty, delayedQty, remainedQty, agreedTotQty;
    InventDim                           inventDim;
    HcmWorker                           planner;
    int                                 maxRun;
    InventSiteId                        siteId;
}

private void calculateRemainedQty(ItemId _itemId, PurchAgreementId _agreeNum, RefRecid _agreementLineRefRecId)
{
    DLX_DeliveryPlanWeeks deliveryPlanWeeks;
    remainedQty = 0;

    while select deliveryPlanWeeks
        where deliveryPlanWeeks.AgreeNum == _agreeNum
        //&& deliveryPlanWeeks.ItemId == _itemId
        && deliveryPlanWeeks.AgreementLine == _agreementLineRefRecId
        && deliveryPlanWeeks.RunNum == maxRun
    {
        if (deliveryPlanWeeks.QtyPlan - deliveryPlanWeeks.QtyRelease > 0)
            remainedQty += deliveryPlanWeeks.QtyPlan - deliveryPlanWeeks.QtyRelease;
    }
}

private str formatName(str _name)
{
    #define.CL("_CL")

    if(subStr(_name, strLen(_name) - 2, 3) == #CL)
        _name = subStr(_name, 0, strLen(_name) - 3);

    return _name;
}

[SRSReportDataSetAttribute(tablestr("DLX_DeliveryPlanReportHeaderTmp"))]
public DLX_DeliveryPlanReportHeaderTmp getDeliveryPlanReportHeaderTmp()
{
    select * from deliveryPlanReportHeaderTmp;
    return deliveryPlanReportHeaderTmp;
}

[SRSReportDataSetAttribute(tablestr("DLX_DeliveryPlanReportTmp"))]
public DLX_DeliveryPlanReportTmp getDeliveryPlanReportTmp()
{
    select * from deliveryPlanTmp;
    return deliveryPlanTmp;
}

private void initFromContract()
{
    vendAccount     = contract.parmVendAccount();
    siteId          = contract.parmInventSiteId(); // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731

}

private void populateHeader()
{
    deliveryPlanReportHeaderTmp.Logo            = DLX_CompanyInfoDim::companyLogo(DLX_CompanyInfoDim::findBySiteId(curext(), siteId)); // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8 - 20170801
    deliveryPlanReportHeaderTmp.VendId          = vendAccount;
    deliveryPlanReportHeaderTmp.VendorName      = VendTable::find(VendAccount).name();
    deliveryPlanReportHeaderTmp.RunDate         = systemDateGet();
    //deliveryPlanReportHeaderTmp.PrimaryAddress  = CompanyInfo::find().primaryAddress();

    deliveryPlanReportHeaderTmp.companyName      = InventSite::find(siteId).Name;
    deliveryPlanReportHeaderTmp.PrimaryAddress   = InventSite::find(siteId).getAddress();

    //planner = HcmWorker::find(DLX_SCMParametersDim::findBySiteId(VendTable::find(vendAccount).InventSiteId).DeliveryPlanPlanner);

    planner = HcmWorker::find(DLX_SCMParametersDim::findBySiteId(siteId).DeliveryPlanPlanner);

    deliveryPlanReportHeaderTmp.PlannerName     = planner.name();
    deliveryPlanReportHeaderTmp.PlannerEmail    = planner.email();
    deliveryPlanReportHeaderTmp.PlannerTel      = planner.phone();
    deliveryPlanReportHeaderTmp.PlannerFax      = planner.DirPerson().primaryFax();

    deliveryPlanReportHeaderTmp.insert();
}

[SysEntryPointAttribute(true)]
public void processReport()
{
    maxRun = 0;

    contract            = this.parmDataContract() as DLX_DeliveryPlanReportDC;

    this.initFromContract();

    // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731
    select maxOf(RunNum) from deliveryPlan
    where deliveryPlan.InventSiteId == siteId; // DLX_SCM_BUG_2839_PurchAgreement - Luca Gir8  - 20170731

    maxRun = deliveryPlan.RunNum;
    deliveryPlan.clear();


    while select deliveryPlan
        where deliveryPlan.Vendor == vendAccount
        && deliveryPlan.RunNum == maxRun
        && (deliveryPlan.QtyAgreeTot != deliveryPlan.QtyReceived)
    {
        deliveryPlanTmp.clear();
        buf2BufbyName_dlx(deliveryPlan, deliveryPlanTmp);
        deliveryPlanTmp.AgreementLine = int642str(deliveryPlan.AgreementLine);
        deliveryPlanTmp.AgreementLineRefRecId = any2int(AgreementLine::find(deliveryPlan.AgreementLine).LineNumber);    // Fix Go live Rimini - 20190114 - Alberto
        //this.calculateRemainedQty(deliveryPlan.Item, deliveryPlan.AgreeNum, deliveryPlanTmp.AgreementLineRefRecId);
        //deliveryPlanTmp.RemainedQty = deliveryPlanTmp.QtyAgreeTot - deliveryPlanTmp.QtyOrd - remainedQty;
        deliveryPlanTmp.Item        = this.formatName(deliveryPlanTmp.Item);
        deliveryPlanTmp.ItemName    = this.formatName(deliveryPlanTmp.ItemName);
        deliveryPlanTmp.insert();

        //if(!siteId)
        //    siteId = deliveryPlan.InventSiteId;
    }

    this.populateHeader();
}

csharp 更新相关子实体

code
public override async Task<UserCategoryDto> Update(UserCategoryDto input)
        {
            CheckUpdatePermission();
            var existingEntity = await Repository.GetAll().Include(x => x.Items).FirstOrDefaultAsync(x => x.Id == input.Id);
            if (existingEntity != null)
            {
                // Update parent
                Repository.GetDbContext().Entry(existingEntity).CurrentValues.SetValues(ObjectMapper.Map<UserCategory>(input));

                // Delete children
                foreach (var existingChild in existingEntity.Items.ToList())
                {
                    if (input.Items.All(c => c.Id != existingChild.Id))
                        existingEntity.Items.Remove(existingChild);
                }

                // Update and Insert children
                foreach (var itemDto in input.Items)
                {
                    var existingChild = existingEntity.Items.SingleOrDefault(c => itemDto.Id > 0 && c.Id == itemDto.Id);

                    if (existingChild != null)
                    {
                        // Update child
                        var item = ObjectMapper.Map<UserCategoryItem>(itemDto);
                        Repository.GetDbContext().Entry(existingChild).CurrentValues.SetValues(item);
                    }
                    else
                    {
                        // Insert child
                        var item = ObjectMapper.Map<UserCategoryItem>(itemDto);
                        existingEntity.Items.Add(item);
                    }
                }

                await CurrentUnitOfWork.SaveChangesAsync();
            }

            return MapToEntityDto(existingEntity);
        }

csharp 场景管理(调试)

SceneManagement.cs
    public IEnumerator ReloadScene()
    {
        float timer = 0;
        if (!debugServer)
        {
            timer = 0.2f;
            //Close Socket
            socketManager.socket.Close();
        }
        yield return new WaitForSeconds(timer);
        UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex);
    }
    public IEnumerator QuitScene()
    {
        float timer = 0;
        if (!debugServer)
        {
            socketManager.socket.Close();
            timer = 0.2f;
        }
        yield return new WaitForSeconds(timer);
        Application.Quit();
    }

csharp 注销应用程序用户数据解析脚本

UserDataManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using LitJson;

public class UserData
{
    public string username;
    public string userLang;
    public string characterIndex;
    public string today;
    public string playtime;
    public string questCount;
    public string[] quest;
    public bool[] questResult;
    public string[] completedQuest;
    public string[] failedQuest;
    public string registeredDate;
    public string favoriteGame;
    public GameData[] gameData;
}
public class GameData
{
    public string[] userGameDataString;
}

public class UserDataManager : MonoBehaviour
{
    [Header("References")]
    public AppManager _AppManager;
    [Space(12)]
    [Header("Settings")]
    public float typingSpeed = 0.125f;
    public float printDelay = 1.0f;
    public float printSpeed = 0.8f;
    [Space(16)]
    #region Global Variables
    [Header("Sounds")]
    public AudioSource successSound;
    public AudioSource failedSound;
    public AudioSource typingSound;
    [Space(12)]
    [Header("User Data Manager")]
    public GameObject endingCreditPanel;
    public Text username;
    public RectTransform slash;
    public Text date;
    public Text playtime;
    public Text[] questTitle = new Text[13];
    public GameObject[] ThankyouPanelMessage = new GameObject[2];
    #endregion
    #region Character Functions
    public int currentCharacterId;
    public GameObject[] characterModel = new GameObject[6];
    public GameObject currentCharacterModel = null;
    #endregion
    #region UserData
    private UserData currentUserData = null;
    private List<GameObject> newCompleted = new List<GameObject>();
    #endregion

    #region Debugging Functions
    public void FakeUserDataParser(int _fakeCharacterId, bool isKorean)
    {
        // Generate Fake Ending Credit
        username.text = "Jonghyeon";
        FixSlashPosition();
        date.text = "2019-07-08";
        playtime.text = "15:18 - 19:28(250m)";
        SetQuestNames();
        
        UserCharacterSelector(_fakeCharacterId);

        currentUserData = new UserData();
        currentUserData.quest = new string[13];
        currentUserData.questResult = new bool[13];
        currentUserData.completedQuest = new string[5];
        currentUserData.failedQuest = new string[8];

        // Parse Data into Data Object
        currentUserData.username = "Jonghyeon";
        if (isKorean)
            currentUserData.userLang="kr";
        else
            currentUserData.userLang="en";
        FixSlashPosition();
        currentUserData.characterIndex = _fakeCharacterId.ToString();
        currentUserData.today = "2019-07-08";
        currentUserData.playtime = "15:18 - 19:28(250m)";
        currentUserData.questResult[0] = true;
        currentUserData.questResult[1] = true;
        currentUserData.questResult[2] = false;
        currentUserData.questResult[3] = false;
        currentUserData.questResult[4] = false;
        currentUserData.questResult[5] = true;
        currentUserData.questResult[6] = false;
        currentUserData.questResult[7] = true;
        currentUserData.questResult[8] = false;
        currentUserData.questResult[9] = false;
        currentUserData.questResult[10] = false;
        currentUserData.questResult[11] = true;
        currentUserData.questResult[12] = false;


        int characterUserCharacterIndex = int.Parse(currentUserData.characterIndex);
        currentCharacterId = characterUserCharacterIndex;
        UserCharacterSelector(characterUserCharacterIndex);
        ThankyouPanelMessageLang(currentUserData.userLang);
    }

    #endregion

    #region User Data Parsing Functions
    public void UserDataParser(JSONObject userData)
    {
        Debug.Log(userData);
        Debug.Log("Got User Data");
        currentUserData = new UserData();
        currentUserData.quest = new string[userData["quests"].Count];
        currentUserData.questResult = new bool[userData["questResults"].Count];
        currentUserData.completedQuest = new string[userData["completedQuest"].Count];
        currentUserData.failedQuest = new string[userData["failedQuest"].Count];

        // Parse Data into Data Object
        currentUserData.username = userData["username"].str;
        currentUserData.userLang = userData["userLang"].str;
        FixSlashPosition();
        currentUserData.characterIndex = userData["characterId"].str;
        currentUserData.today = userData["today"].str;
        currentUserData.playtime = userData["playtime"].str;
        for (int i = 0; i < userData["quests"].Count; i++)
        {
            currentUserData.quest[i] = userData["quests"][i].str;
        }
        for (int i = 0; i < userData["questResults"].Count; i++)
        {
            currentUserData.questResult[i] = (bool)userData["questResults"][i].b;
        }
        for (int i = 0; i < userData["completedQuest"].Count; i++)
        {
            currentUserData.completedQuest[i] = userData["completedQuest"][i].str;
        }
        for (int i = 0; i < userData["failedQuest"].Count; i++)
        {
            currentUserData.failedQuest[i] = userData["failedQuest"][i].str;
        }

        int characterUserCharacterIndex = int.Parse(currentUserData.characterIndex);
        currentCharacterId = characterUserCharacterIndex;
        UserCharacterSelector(characterUserCharacterIndex);
        ThankyouPanelMessageLang(currentUserData.userLang);
    }
    public void ThankyouPanelMessageLang(string userLang)
    {
        if (userLang == "en")
        {
            ThankyouPanelMessage[0].SetActive(true);
            ThankyouPanelMessage[1].SetActive(false);
        }
        else
        {
            ThankyouPanelMessage[0].SetActive(false);
            ThankyouPanelMessage[1].SetActive(true);
        }

    }
    public void UserCharacterSelector(int _currentCharacterId)
    {
        Debug.Log("currentCharacter Id: " + _currentCharacterId);
        for (int i = 0; i < characterModel.Length; i++)
        {
            if (i == _currentCharacterId)
            {
                characterModel[i].SetActive(true);
            }
            else
            {
                characterModel[i].SetActive(false);
            }
        }
        currentCharacterModel = characterModel[_currentCharacterId];
        // Do Something with this gameObject.
    }
    public void EndingCreditManager()
    {

            Debug.Log(currentUserData.username + "," + currentUserData.today + "," + currentUserData.playtime);
            username.text = currentUserData.username;
            date.text = currentUserData.today;
            playtime.text = currentUserData.playtime;
            StartCoroutine(PrintQuests(printDelay, printSpeed));



    }
    #endregion
    #region Animation & Helpers
    public void SetQuestNames()
    {
        questTitle[0].text = "[Parallel Me]";
        questTitle[1].text = "[Campfire]";
        questTitle[2].text = "[Pop Tag!]";
        questTitle[3].text = "[The 3rd Supply Base]";
        questTitle[4].text = "[1,000,000/3sec]";
        questTitle[5].text = "[/Quiz Quiz]";
        questTitle[6].text = "[Lorna and Pann]";
        questTitle[7].text = "[Dimension Library]";
        questTitle[8].text = "[Hidden Track]";
        questTitle[9].text = "[Eye Tracking]";
        questTitle[10].text = "[Behind the Game]";
        questTitle[11].text = "[NPC]";
        questTitle[12].text = "[Hidden Message]";
    }
    public void FixSlashPosition()
    {
        float usernameWidth = username.preferredWidth;
        Vector3 slashPos = slash.anchoredPosition;
        slash.anchoredPosition = new Vector3(usernameWidth / 2 - usernameWidth - 30, slashPos.y, slashPos.z);
    }
    public IEnumerator PrintQuests(float _printDelay, float _printSpeed)
    {
        yield return new WaitForSeconds(_printDelay);
        for (int i = 0; i < currentUserData.questResult.Length; i++)
        {
            QuestResultAnim(i);
            yield return new WaitForSeconds(_printSpeed);
        }
        Debug.Log("Quest Printing Done");


    }
    public void QuestResultAnim(int _questIndex)
    {
        if (currentUserData.questResult[_questIndex])
        {
            StartCoroutine(TypeWriting(_questIndex, questTitle[_questIndex], " Completed", true));
        }
        else
        {
            StartCoroutine(TypeWriting(_questIndex, questTitle[_questIndex], " Failed", false));
        }
    }

    public IEnumerator TypeWriting(int _questIndex, Text targetText, string textToAdd, bool isCompleted)
    {
        foreach (char c in textToAdd)
        {
            targetText.text += c;
            yield return new WaitForSeconds(typingSpeed);
        }
        ResultAnimEnd(_questIndex, isCompleted);

    }
    public void ResultAnimEnd(int _questIndex, bool isCompleted)
    {
        // Change Color & Play Sound.
        if (isCompleted)
        {
            GameObject newCompletedText = new GameObject("newCompleted");
            newCompleted.Add(newCompletedText);
            // newCompletedText.tag = "ResultText";
            RectTransform textOrigin = questTitle[_questIndex].gameObject.GetComponent<RectTransform>();
            newCompletedText.transform.SetParent(questTitle[_questIndex].gameObject.transform);
            newCompletedText.AddComponent<Text>();
            newCompletedText.GetComponent<Text>().text = "Completed";
            newCompletedText.GetComponent<Text>().font = questTitle[_questIndex].font;
            newCompletedText.GetComponent<Text>().fontSize = questTitle[_questIndex].fontSize;
            newCompletedText.GetComponent<RectTransform>().anchoredPosition = new Vector2(textOrigin.anchoredPosition.x, textOrigin.anchoredPosition.y);
            newCompletedText.GetComponent<RectTransform>().localPosition = new Vector3(0, 0, 0);
            newCompletedText.GetComponent<RectTransform>().eulerAngles = textOrigin.eulerAngles;
            newCompletedText.GetComponent<RectTransform>().sizeDelta = textOrigin.sizeDelta;
            newCompletedText.GetComponent<RectTransform>().localScale = textOrigin.localScale;
            newCompletedText.GetComponent<Text>().color = new Color32(32, 166, 220, 255);
            // newCompletedText.AddComponent<Shadow>();
            newCompletedText.AddComponent<Outline>().effectColor = new Color32(32, 166, 220, 255);
            newCompletedText.GetComponent<Outline>().effectDistance = new Vector2(0.1f, -0.1f);
            // newCompletedText.AddComponent<Shadow>().effectColor = new Color32(32, 166, 220, 255);
            float questResultTextWidth = questTitle[_questIndex].preferredWidth;
            newCompletedText.GetComponent<RectTransform>().anchoredPosition = new Vector2(questResultTextWidth / 2 - 8, newCompletedText.GetComponent<RectTransform>().anchoredPosition.y);

            successSound.Play(0);
        }
        else
        {
            questTitle[_questIndex].color = new Color32(255, 255, 255, 100);
            failedSound.Play(0);
        }

    }
    public void RecoverEndingCreditPanel()
    {
        Debug.Log(newCompleted.Count);
        foreach (GameObject completedText in newCompleted)
        {
            Destroy(completedText);
        }
        foreach(Text questText in questTitle){
            questText.color = new Color32(255, 255, 255, 255);
        }
        newCompleted.Clear();
        Debug.Log(newCompleted.Count);
        SetQuestNames();
    }
    #endregion


}
SocketManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using SocketIO;
using UnityEngine.Video;
using System;
using SocketMessages;

public class SocketManager : MonoBehaviour
{

    #region Variables

    [Header("Socket")]
    public string serverIP;
    public string serverPort;
    public bool isConnected;
    [Space(8)]

    [Header("UI")]
    public GameObject connectionErrorPanel;
    public InputField inputIPAdress;
    public InputField inputPort;
    [Space(8)]

    [Header("Scripts Socket")]
    public SocketIOComponent socket;
    public SocketEmitMessageList socketEmitMessageList;
    SocketSettings socketSettings;

    [Header("Scripts Global")]
    [SerializeField] AppManager appManager;
    public UserDataManager _UserDataManager;

    #endregion


    #region Standard Function

    private void Awake()
    {
        // Load Socket settings
        LoadSettings();
    }

    public void Start()
    {

        // Return in debug mode
        if (appManager.debugServer) return;

        // Connection
        socket.gameObject.SetActive(true);
        socket.Connect();

        socket.On("open", TestOpen);
        socket.On("error", TestError);
        socket.On("close", TestClose);
        socket.On("unity-reload", ReloadApp);
        socket.On("unity-quit", QuitApp);

        socket.On("logout-tagging", ManageAppStarter);
        socket.On("printing-done", PrintingDone);

    }

    public void Update()
    {
        if (appManager.debugServer) return;

        // Display Error setting Pannel to configure IP adress of nodejs server
        if (isConnected && connectionErrorPanel.activeSelf)
        {
            connectionErrorPanel.SetActive(false);
            connectionErrorPanel.transform.GetChild(4).gameObject.SetActive(true);
        }
        else if (!isConnected && !connectionErrorPanel.activeSelf)
        {
            connectionErrorPanel.SetActive(true);
            inputIPAdress.placeholder.GetComponent<Text>().text = serverIP;
            inputPort.placeholder.GetComponent<Text>().text = serverPort;
            StartCoroutine(DisableBlocker(0.2f));
        }
    }

    #endregion
    #region Logout Experience
    public void StartPrinting()
    {
        if (appManager.debugServer) return;
        Debug.Log("Send printing signal");
        socket.Emit("print-receipt");
    }


    public void EndOfExperience()
    {
        if (appManager.debugServer) Debug.Log("End of experience, but in server debug mode"); return;
        socket.Emit("end-of-experience");
    }
    #endregion


    #region Socket Settings Function

    public void UpdateServerAdress()
    {
        socket.url = "ws://" + serverIP + ":" + serverPort + "/socket.io/?EIO=4&transport=websocket";
    }

    public IEnumerator DisableBlocker(float _wait)
    {
        yield return new WaitForSeconds(_wait);
        if (connectionErrorPanel.activeSelf)
            connectionErrorPanel.transform.GetChild(4).gameObject.SetActive(false);
    }

    #endregion


    #region Node JS Common Function

    public void SendMessageToNode(string _message, string _contents)
    {
        //Debug.Log(_message);
        JSONObject jsonContents = new JSONObject(_contents);
        socket.Emit(_message, jsonContents);
    }

    public void TestOpen(SocketIOEvent e)
    {
        Debug.Log("Local NodeJS server connected");
        //Debug.Log("[SocketIO] Open received: " + e.name + " " + e.data);
        isConnected = true;
    }

    public void TestError(SocketIOEvent e)
    {
        Debug.Log("Local NodeJS server disconnected:error" + e);
        //Debug.Log("[SocketIO] Error received: " + e.name + " " + e.data);
        if (isConnected)
            isConnected = false;
    }

    public void TestClose(SocketIOEvent e)
    {
        Debug.Log("Local NodeJS server disconnected");
        //Debug.Log("[SocketIO] Close received: " + e.name + " " + e.data);
        isConnected = false;
    }

    public void ReloadApp(SocketIOEvent e)
    {
        //Debug Message and Data
        //Debug.Log("[SocketIO]Reload: " + e.name);
        StartCoroutine(appManager.ReloadScene());
    }

    public void QuitApp(SocketIOEvent e)
    {
        //Debug Message and Data
        //Debug.Log("[SocketIO]Quit: " + e.name);
        StartCoroutine(appManager.QuitScene());
    }

    public void ManageAppStarter(SocketIOEvent e)
    {
        if (e.data == null) return;
        if (e.data.GetField("userData") == null) return;
        
        JSONObject userData = e.data.GetField("userData");
        appManager.JoinTheApp();
        _UserDataManager.UserDataParser(userData);
    }

    public void PrintingDone(SocketIOEvent e)
    {
        Debug.Log("Printing Done, timing issue");
        // appManager.ThankyouForPlaying();
    }

    #endregion


    #region UI Socket Settings

    public void ChangeIpAdress(string _ip, string _port)
    {
        serverIP = _ip;
        serverPort = _port;
    }

    public void UpdateIpAdress(string _ip, string _port)
    {
        SaveServerSettings(_ip, _port);
        connectionErrorPanel.SetActive(false);
        UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex);
    }

    public void SaveSettingsButton()
    {
        string _newIp = inputIPAdress.text;
        if (_newIp == "")
            _newIp = inputIPAdress.placeholder.GetComponent<Text>().text;
        string _newPort = inputPort.text;
        if (_newPort == "")
            _newPort = inputPort.placeholder.GetComponent<Text>().text;
        UpdateIpAdress(_newIp, _newPort);
    }

    #endregion


    #region Player Prefabs 

    public void LoadSettings()
    {
        socketSettings = new SocketSettings();

        if (PlayerPrefs.HasKey("ipAdress") && PlayerPrefs.HasKey("port"))
            ChangeIpAdress(PlayerPrefs.GetString("ipAdress"), PlayerPrefs.GetString("port"));
        else
            UpdateIpAdress("127.0.0.1", "8888");

        UpdateServerAdress();

    }

    public void SaveServerSettings(string _newIp, string _newPort)
    {
        socketSettings.ipAdress = _newIp;
        PlayerPrefs.SetString("ipAdress", _newIp);
        socketSettings.port = _newPort;
        PlayerPrefs.SetString("port", _newPort);
    }

    #endregion

}

csharp 顶点对象生成器

VertexObjectSpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class VertexObjectSpawner : MonoBehaviour
{

    #region Variables
    public GameObject[] objects;
    public Mesh mesh;
    public GameObject spawnHolder;
    public Transform offsetter;
    public float objectSpawnSpeed = 1f;
    public Vector3 inverseRotation;
    public bool coroutined = true;
    public KeyCode togglePhysicsKey = KeyCode.Space;
    public KeyCode toggleCoroutinedPhysicssKey = KeyCode.T;
    public bool correctRotation = true;
    public bool toggleWithCoroutine = false;
    public bool toggleWithCoroutineReverse = false;
    #endregion
    #region Texture Color Parsing
    public GameObject model;
    public Texture2D sourceTex;
    public float warpFactor = 1.0F;
    private Texture2D destTex;
    private Color[] destPix;
    private Color[] vertColor;
    #endregion

    private Quaternion objectRotation;
    private WaitForSeconds wait;
    private List<GameObject> spawned = new List<GameObject>();

    private void Awake(){
        GetTextureVertexColor();
    }
    private void Start()
    {
        if (!spawnHolder)
        {
            spawnHolder = new GameObject("Spawn Holder");
        }
        wait = new WaitForSeconds(objectSpawnSpeed);
        if (coroutined)
        {
            StartCoroutine(Spawn());
        }
        else
        {
            Spawn01();
        }
        
    }

    private void Update()
    {
        if (Input.GetKeyDown(togglePhysicsKey))
        {
            if (toggleWithCoroutine)
            {
                StartCoroutine(TogglePhysics01(!spawned[spawned.Count - 1].GetComponent<Rigidbody>().isKinematic, toggleWithCoroutineReverse));
            }
            else
            {
                TogglePhysics(!spawned[spawned.Count - 1].GetComponent<Rigidbody>().isKinematic);
            }
        }
        if (Input.GetKeyDown(toggleCoroutinedPhysicssKey))
        {
            toggleWithCoroutineReverse = !toggleWithCoroutineReverse;
            toggleWithCoroutine = !toggleWithCoroutine;
        }
    }

    private IEnumerator Spawn()
    {
        objectRotation = offsetter.rotation;
        for (int i = 0; i < mesh.vertexCount; i++)
        {
            GameObject spawn = Instantiate(objects[Random.Range(0, objects.Length)], mesh.vertices[i] + offsetter.position, Quaternion.Euler(inverseRotation), spawnHolder.transform);
            
            spawn.GetComponent<Renderer>().sharedMaterial.color = vertColor[i];
            spawned.Add(spawn);
            yield return objectSpawnSpeed;
        }
        if (correctRotation)
        {
            offsetter.rotation = Quaternion.identity;
        }
    }

    private void Spawn01()
    {
        objectRotation = offsetter.rotation;
        for (int i = 0; i < mesh.vertexCount; i++)
        {
            GameObject spawn = Instantiate(objects[Random.Range(0, objects.Length)], mesh.vertices[i] + offsetter.position, Quaternion.Euler(inverseRotation), spawnHolder.transform);
            spawn.GetComponent<Renderer>().sharedMaterial.color = vertColor[i];
            spawned.Add(spawn);
        }
        if (correctRotation)
        {
            offsetter.rotation = Quaternion.identity;
        }
    }

    private void TogglePhysics(bool kinematic)
    {
        for (int i = 0; i < spawned.Count; i++)
        {
            spawned[i].GetComponent<Rigidbody>().isKinematic = kinematic;
        }
    }

    private IEnumerator TogglePhysics01(bool kinematic, bool reverse)
    {
        if (reverse)
        {
            for (int i = spawned.Count - 1; i > 0; i--)
            {
                spawned[i].GetComponent<Rigidbody>().isKinematic = kinematic;
                yield return objectSpawnSpeed;
            }
        }
        else
        {
            for (int i = 0; i < spawned.Count; i++)
            {
                spawned[i].GetComponent<Rigidbody>().isKinematic = kinematic;
                yield return objectSpawnSpeed;
            }
        }
    }
    public void GetTextureVertexColor()
    {
        Vector3[] vertices = mesh.vertices;
        Vector2[] uvs = new Vector2[vertices.Length];
        for(int i =0; i< uvs.Length; i++){
            uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
        }
        destTex = new Texture2D(sourceTex.width, sourceTex.height);
        destPix = new Color[destTex.width * destTex.height];

        vertColor = new Color[vertices.Length];
        
        // Trying to map the uv color to instantiated cubes.....
        int y = 0;
        while (y < destTex.height / Mathf.Sqrt(uvs.Length))
        {
            int x = 0;
            while (x < destTex.width / Mathf.Sqrt(uvs.Length))
            {
                // float xFrac = x * uvs[y * destTex.width + x].x / (destTex.width - 1);
                // float yFrac = y * uvs[y * destTex.width + x].y / (destTex.height - 1);
                float xFrac = x * uvs[(x+1)*(y+1)].x / (destTex.width - 1);
                float yFrac = y * uvs[(x+1)*(y+1)].y / (destTex.height - 1);
                // float warpXFrac = Mathf.Pow(xFrac, warpFactor);
                // float warpYFrac = Mathf.Pow(yFrac, warpFactor);
                // destPix[y * destTex.width + x] = sourceTex.GetPixelBilinear(xFrac, yFrac);
                vertColor[y * destTex.width + x] = sourceTex.GetPixelBilinear(xFrac, yFrac);
                x++;
            }
            y++;
        }
        Mesh modelMesh = model.GetComponent<MeshFilter>().mesh;
        Color32[] colors = new Color32[vertices.Length];
        int j = 0;
        while (j < vertices.Length) {
            colors[j] = Color.Lerp(Color.red, Color.green, vertices[j].y);
            j++;
        }
        modelMesh.colors32 = colors;

        Debug.Log(uvs.Length);
        destTex.SetPixels(destPix);
        Debug.Log(vertColor.Length);
        Debug.Log(destTex.height / Mathf.Sqrt(uvs.Length) * destTex.width / Mathf.Sqrt(uvs.Length));
        destTex.Apply();
        // GetComponent<Renderer>().material.mainTexture = destTex;
    }
}

csharp 使用协程的定时器(不推荐使用,需要清理)

UserTimer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(AppManager))]
public class UserTimer : MonoBehaviour
{
    #region Timer Coroutines
    public IEnumerator _NoshowTimer(int timeLimit)
    {
        for (int i = 0; i < timeLimit; i++)
        {
            Debug.Log("Noshow Timer : " + (timeLimit - i));
            yield return new WaitForSeconds(timeLimit / timeLimit);
        }
        this.gameObject.GetComponent<AppManager>().ToIdleScene();
        this.gameObject.GetComponent<AppManager>().noshowTimerStarted = false;
    }
    public IEnumerator _InteractionTimer(int timeLimit)
    {

        for (int i = 0; i < timeLimit; i++)
        {
            Debug.Log("Interaction Timer : " + (timeLimit - i));
            yield return new WaitForSeconds(timeLimit / timeLimit);
        }
        this.gameObject.GetComponent<AppManager>().ToIdleScene();
    }
    public IEnumerator _LostTrackingTimer(int timeLimit)
    {
        for (int i = 0; i < timeLimit; i++)
        {
            Debug.Log("Lost Tracking : " + (timeLimit - i));
            yield return new WaitForSeconds(timeLimit / timeLimit);
        }
        this.gameObject.GetComponent<AppManager>().ToIdleScene();
    }
    #endregion
}

csharp 套接字管理器(需要清理)

SocketManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using SocketIO;
using SocketMessages;

public class SocketManager : MonoBehaviour
{
    [Header("Managers")]
    public AppManager _AppManager;
    [Space(8)]
    public CharacterMatchingManager _CharacterMatchingManager;
    public UserDataPanelManager _UserDataPanelManager;
    public EffectsManager _EffectsManager;
    [Header("Socket")]
    public string serverIP;
    public string serverPort;
    public bool isConnected;
    Dictionary<string, string> data;

    [Space(8)]

    [Header("UI")]
    public GameObject connectionErrorPanel;
    public InputField inputIPAddress;
    public InputField inputPortAddress;
    [Space(8)]

    [Header("Socket_Scripts")]
    public SocketSettings _SocketSettings;
    public SocketIOComponent socket;
    public SocketEmitMessageList socketEmitMessageList;


    private void Awake()
    {
        // Load Socket Settings.
        LoadSettings();
    }

    public void Start()
    {
        if (_AppManager.serverDebugging) return;
        // Connect
        socket.gameObject.SetActive(true);
        socket.Connect();

        socket.On("open", TestOpen);
        socket.On("error", TestError);
        socket.On("close", TestClose);
        socket.On("mirror", TaggingListener);
        socket.On("emotion", GetFacialEmotionData);

        data = new Dictionary<string, string>();
    }

    public void Update()
    {
        if (_AppManager.serverDebugging) return;

        if (Input.GetKeyDown(KeyCode.E))
        {
            if (isConnected)
            {
                EndOfExperience();
            }
            else
            {
                Debug.Log("Not Connected to Server");
            }
        }
        // Display Error setting Pannel to configure IP adress of nodejs server
        if (isConnected && connectionErrorPanel.activeSelf)
        {
            connectionErrorPanel.SetActive(false);
        }
        else if (!isConnected && !connectionErrorPanel.activeSelf)
        {
            connectionErrorPanel.SetActive(true);
            inputIPAddress.placeholder.GetComponent<Text>().text = serverIP;
            inputPortAddress.placeholder.GetComponent<Text>().text = serverPort;
        }
    }

    #region Socket Settings Function

    public void UpdateServerAdress()
    {
        socket.url = "ws://" + serverIP + ":" + serverPort + "/socket.io/?EIO=4&transport=websocket";
        Debug.Log("Server Address Updated : " + socket.url);
    }

    #endregion

    #region Node JS Common Function
    public void TaggingListener(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] User Tagged");
        Debug.Log(e.data);

        isConnected = true;
        // Now The Interaction Begins.
        _AppManager.isOccupied = true;

        if (e.data == null)
        {
            Debug.Log("There is no data from API");
            return;
        }
        if (e.data.GetField("username") != null && e.data.GetField("characterId") != null && e.data.GetField("language") != null)
        {
            string createdAt = "2019";
            if (e.data.GetField("createdAt") != null)
            {
                createdAt = e.data.GetField("createdAt").str;
            }
            string username = e.data.GetField("username").str;
            string characterIdStr = e.data.GetField("characterId").str;
            int characterId = int.Parse(characterIdStr);
            string userLang = e.data.GetField("language").str;
            // Do something with this user dataset.
            _CharacterMatchingManager.currentCharacterIndex = characterId;
            _UserDataPanelManager.UpdateUserData(username, createdAt);
            _UserDataPanelManager.lang = userLang;
            _UserDataPanelManager.UpdateUserTagline(characterId);
            _EffectsManager.CurrentCharacterRenderer(characterId);

            // To Interaction Scene, Send Data To The Script Also.
            _AppManager.ToInteractionScene();
        }
    }
    public void EndOfExperience()
    {
        if (_AppManager.serverDebugging)
        {
            Debug.Log("Experience ends, but in server debugging mode");
            return;
        }

        EndExperience newEndExperience = new EndExperience();
        newEndExperience.experience = "mirror";
        newEndExperience.data = "experience";
        string json = JsonUtility.ToJson(newEndExperience);
        Debug.Log(json);
        SendMessageToNode("experience", json);
    }
    public void SendMessageToNode(string _message, string _contents)
    {
        if (_AppManager.serverDebugging)
        {
            Debug.Log("in Server debugging mode");
            return;
        }
        JSONObject jsonContents = new JSONObject(_contents);
        socket.Emit(_message, jsonContents);
    }
    public void TestOpen(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] Open received: " + e.name + " " + e.data);
        isConnected = true;
        Debug.Log(isConnected);
    }

    public void TestError(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] Error received: " + e.name + " " + e.data);
        if (isConnected) isConnected = false;
    }

    public void TestClose(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] Close received: " + e.name + " " + e.data);
        isConnected = false;
    }
    public void ReloadApp(SocketIOEvent e)
    {
        //Debug Message and Data
        //Debug.Log("[SocketIO]Reload: " + e.name);
        // StartCoroutine(gameManager.ReloadScene());
    }

    public void QuitApp(SocketIOEvent e)
    {
        //Debug Message and Data
        //Debug.Log("[SocketIO]Quit: " + e.name);
        // StartCoroutine(gameManager.QuitScene());
    }

    #endregion
    #region Face Analysis Functions
    public void GetFacialEmotionData(SocketIOEvent e)
    {
        if (e.data == null) { return; }
        if (e.data.GetField("class") != null)
        {
            if (e.data.GetField("class"))
            {
                Debug.Log("Server said, " + e.data.GetField("class"));
                // Invoke CharacterFaceSwap Here
                string currentFaceIndexString = e.data.GetField("class").ToString();
                if (int.TryParse(currentFaceIndexString, out int _currentFaceIndex))
                {
                    if (_currentFaceIndex < 5)
                    {
                        if (_currentFaceIndex != 2)
                        {
                            _CharacterMatchingManager.currentFaceIndex = _currentFaceIndex;
                            //TODO fix character emotions(how many?)
                        }

                    }

                }
                else
                {
                    Debug.Log("It should be a number");
                }
            }
        }
    }
    #endregion

    #region UI Socket Settings

    public void ChangeIpAdress(string _ip, string _port)
    {
        serverIP = _ip;
        serverPort = _port;
        UpdateServerAdress();
    }

    public void UpdateIpAdress(string _ip, string _port)
    {
        // ChangeIpAdress(_ip, _port);
        SaveSettings(_ip, _port);
        connectionErrorPanel.SetActive(false);

    }

    public void SaveInputButton()
    {
        string _newIp = inputIPAddress.text;
        string _newPort = inputPortAddress.text;
        if (_newIp == "")
            _newIp = inputIPAddress.placeholder.GetComponent<Text>().text;
        if (_newPort == "")
            _newPort = inputPortAddress.placeholder.GetComponent<Text>().text;
        UpdateIpAdress(_newIp, _newPort);
    }

    #endregion
    #region Load & Save Socket Settings

    public void LoadSettings()
    {
        _SocketSettings.LoadFromJson();
        if (_SocketSettings.ipAddress != null && _SocketSettings.port != null)
        {
            Debug.Log(_SocketSettings.ipAddress + ":" + _SocketSettings.port);
            ChangeIpAdress(_SocketSettings.ipAddress, _SocketSettings.port);
            return;
        }
        else
            UpdateIpAdress("127.0.0.1", "80");

        UpdateServerAdress();
    }

    public void SaveSettings(string _newIp, string _newPort)
    {
        _SocketSettings.ipAddress = _newIp;
        _SocketSettings.port = _newPort;
        _SocketSettings.SaveToJson();
        _AppManager.ReloadScene();
    }

    #endregion

}

csharp 按另一个元素的大小设置UI元素的位置

prefferedWidth.cs
float userTaglineWidth = userTaglineText.preferredWidth;
userTanlineCursor.transform.position = new Vector3(userTaglineText.transform.position.x + userTaglineWidth + 50,userTanlineCursor.transform.position.y,userTanlineCursor.transform.position.z);

csharp 使用箭头键调试导航功能

DebugNavigationManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class DebugNavigationManager : MonoBehaviour
{
    public AppManager _Appmanager;
    EventSystem system;
    public GameObject settingsPanel;
    public GameObject TrackingManager;
    public GameObject SettingManager;
    public GameObject initSelection;

    public bool inSettingMode = false;
    public bool findFirstSelectable = false;

    void Start()
    {
        system = EventSystem.current;
    }
    void Update()
    {   if(_Appmanager.isDebugging){
            ShortcutsForSetting();
            TabNavigation();
        }
    }
    public void ToggleSettingsPanel()
    {
        if (settingsPanel.activeSelf)
        {
            settingsPanel.SetActive(false);
            inSettingMode = false;
        }
        else
        {
            settingsPanel.SetActive(true);
            inSettingMode = true;
        }
    }
    public void ShortcutsForSetting()
    {
        // Ctrl + T to show setting panel.
        if (Input.GetKeyDown(KeyCode.T))
        {
            if (Input.GetKey(KeyCode.LeftControl))
            {
                ToggleSettingsPanel();
                if(inSettingMode){
                    InputField inputfield = initSelection.GetComponent<InputField>();
                    if (inputfield != null)inputfield.OnPointerClick(new PointerEventData(system));

                    system.SetSelectedGameObject(initSelection.gameObject, new BaseEventData(system));
                }
            }
        }
        if (inSettingMode)
        {
            // Ctrl + Y to Init Camera Calibration.
            if (Input.GetKeyDown(KeyCode.Y))
            {
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    TrackingManager.GetComponent<CamCalibration>().CamCaliInit();
                }
            }
            // Ctrl + S to Save Settings.
            // Ctrl + Shift + S to Save Settings into Default Settings File.
            if (Input.GetKeyDown(KeyCode.S))
            {
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    SettingManager.GetComponent<SettingManager>().SaveSettings(0);

                    if (Input.GetKey(KeyCode.LeftShift))
                    {
                        SettingManager.GetComponent<SettingManager>().SaveSettings(1);
                    }
                }
            }
            // Ctrl + L to Load Settings.
            // Ctrl + Shift + L to Load Settings from Default Settings File.
            if (Input.GetKeyDown(KeyCode.L))
            {
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    SettingManager.GetComponent<SettingManager>().LoadSettings(0);
                    if (Input.GetKey(KeyCode.LeftShift))
                    {
                        SettingManager.GetComponent<SettingManager>().LoadSettings(1);
                    }
                }
            }
        }
    }
    private void TabNavigation()
    {
        if (inSettingMode)
        {
            if (Input.GetKeyDown(KeyCode.Tab))
            {
                if (Input.GetKey(KeyCode.LeftShift))
                {
                    Selectable prev = system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnLeft();
                    if (prev != null)
                    {
                        InputField inputfield = prev.GetComponent<InputField>();
                        if (inputfield != null)
                            inputfield.OnPointerClick(new PointerEventData(system));

                        system.SetSelectedGameObject(prev.gameObject, new BaseEventData(system));
                    }
                }
                else
                {
                    Selectable next = system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnRight();
                    if (next != null)
                    {
                        InputField inputfield = next.GetComponent<InputField>();
                        if (inputfield != null) inputfield.OnPointerClick(new PointerEventData(system));

                        system.SetSelectedGameObject(next.gameObject, new BaseEventData(system));
                    }
                }
            }
            if (Input.GetKeyDown(KeyCode.UpArrow))
            {
                Selectable up = system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnUp();
                if (up != null)
                {
                    InputField inputfield = up.GetComponent<InputField>();
                    if (inputfield != null) inputfield.OnPointerClick(new PointerEventData(system));

                    system.SetSelectedGameObject(up.gameObject, new BaseEventData(system));
                }
            }
            if (Input.GetKeyDown(KeyCode.DownArrow))
            {
                Selectable down = system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnDown();
                if (down != null)
                {
                    InputField inputfield = down.GetComponent<InputField>();
                    if (inputfield != null) inputfield.OnPointerClick(new PointerEventData(system));

                    system.SetSelectedGameObject(down.gameObject, new BaseEventData(system));
                }
            }
            if (Input.GetKeyDown(KeyCode.LeftArrow))
            {
                Selectable left = system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnLeft();
                if (left != null)
                {
                    InputField inputfield = left.GetComponent<InputField>();
                    if (inputfield != null) inputfield.OnPointerClick(new PointerEventData(system));

                    system.SetSelectedGameObject(left.gameObject, new BaseEventData(system));
                }
            }
            if (Input.GetKeyDown(KeyCode.RightArrow))
            {
                Selectable right = system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnRight();
                if (right != null)
                {
                    InputField inputfield = right.GetComponent<InputField>();
                    if (inputfield != null) inputfield.OnPointerClick(new PointerEventData(system));

                    system.SetSelectedGameObject(right.gameObject, new BaseEventData(system));
                }
            }
        }
    }
}