Blog logoJustZht

Blog logo

Justin Fincher

Just a random person.

2018.10.14

 • 

偶尔翻了下 timehop 才发现刚好一年前的今天是校招季,对比下最近这两个时间还挺接近。
当时我恐怕不知道后面一整年的自己会那样疲于奔波,真是漫长的一年啊。

LogMeow

 • 

写 Skyline 的过程中发现 Android Studio 的 Logcat 界面经常假死,于是自己尝试写了一个 Logcat 界面,基于 kotlin-graphics/imguicosysoft/device。dear IMGUI 比 Unity 的 IMGUI 强大许多,写起来也比较有趣。 导出后就是一个 jar,可以运行在 macOS / Windows 上。

2018.8.3

 • 

Skyline 2.0 写了一半多了,因为重写的缘故遇到了一些之前没遇到的问题,估计发包还要推后一些。
写 Skyline 需要很多 Android 测试机,因此从家里搜了五六台设备用于测试,其中有一台 15 年买的坚果 Y601。这台 Y601 从买回来之后就一直只要卡顿就自动重启,之前折腾了半天总算是升级到了 Smartisan OS 3.x 版本,这次发现系统提示可以升级到 4.2 进入升级界面却显示无网络,因此点了重置手机想看看清楚数据后会不会好些,哪知道重置后卡在了激活界面提示无法连接网络。在论坛里搜了半天后才知道 3.8 以下版本网络激活的通道关闭了,只能手机卡激活。而我也没有大卡可以塞进去激活,因此直接下了一个 OTA 包 sideload 进去了。
这个事情让我哭笑不得,一个做手机的厂,自家深度定制的 OS 在版本兼容上出了各种问题,之前 2.x 版本升级签名不对,需要手动安装新的系统更新 apk 才能检测新的 OTA,然后是应用商店里的微信签名不对导致更新后数据丢了,还有这次老系统的激活验证通道直接关闭,实在不像是一个正常厂商干的事情,毕竟我这种独立开发者玩票随时弃坑就算了,商业公司关闭接口竟然也没有 API fallback 或者远程弹窗提示,让普通用户干瞪眼送修吗,况且 Google 地图应用现在仍然可以在十年前的 Android 0.9 系统上查看,iOS 6 的 App Store 仍然能获取商店信息和下载更新,这些公司对老系统的接口兼容性可算是比锤子这种一个版本号就过不去的做法不知成熟到哪里去。
这个事情让我坚定了自己的软件最好不要带服务端的想法,毕竟之前就写过这个事情,优雅但因为服务关停而无法使用的软件太多了,还是数据自给自足的软件更有生命力些。
这个事情也让我对自己发展的选择隐隐的担忧更加深了些。身边的人都去大厂锻炼,不出意外我也是要去腾讯的人(目前因为延期毕业和一个其他事情暂时推到八月中下了),去大厂相比创业公司主要就是看工程,看这类流程和大项目才会有的问题,而如果我又去折腾一些不成熟或者求快的东西,我会真的有收获吗,我还是没想通。

2018.7.29

 • 

FKJ Beijing Live

去北京看了场 FKJ 的演出,应该是北京首演了。

FKJ 是这两年来最喜欢的音乐家,说来有趣,我的 Skyline 动态壁纸 就是听着他的 Skyline 写出来的,软件名字也因此或多或少地顺手叫了 Skyline。
之前这个票价让我觉得有点太便宜了(或许是早鸟票的原因),毕竟是大佬来华。初到现场时以为不会有太多人,哪知道排了两层楼的队伍,组织有些不利等到了十点才正式开始。至于 Live 怕是不可言说只能亲身感受,最后返场的时间也超长,把 Vibin Out 和 So Much to Me 都演了,十分满足。
顺带一提,暖场的 HFigures 也不错,还专门搜了下,Deep Diving 挺好听,喵喵也喜欢这类 Jazz hiphop。

Skyline LWP

2.0 正在编写。的确还是跳票了,由于学校的考试,课设,延期毕业,个人的办签证,去北京处理东西等其他事项,2.0 从三月份拖到现在,让我自己都有一种赚了钱就跑的感觉,但是这么就太不厚道了,而且 1.0 版本问题的确很多,于是最近有些空,完全重写了下。
这次仍然没有摆脱 Unity,原因是 Android 上暂时没找到一个现代的的对开发友好的 Scene Graph / 游戏引擎:

  • ViroCore API 设计非常适合有 SceneKit 经验的人,但是暂时不支持自定义着色器,因此没办法做到根据高度图实时 Vertex Offest,而如果手动构造 Mesh 的话为啥不用 Unity 有现成的 Mapbox SDK 呢?
  • Rajawali 太老了,以及文档不够
  • libGDX 是一个跨平台的引擎,然后生成的 Gradle 项目是 Native 和游戏主干分开的,我试了一会还是觉得太憋屈了
  • UrhoSharp 配合 Xamarian 差点就成功了。Urho3D 本身功能强大,但是死在了不知道怎么用 C# 绑定去把 UrhoSharp 的视图扔到 Wallpaper.Engine 里面去
  • Sceneform,谷歌亲生框架,但是目前只能在 ARCore 里面用
  • Ogre,emmm 我忘了,反正应该也是觉得用起来难受

因此,在没一个能打的情况下,Skyline 2.0 还是用了 Unity,不过这次带了 LWRP,期许能对移动设备更友好一些。

至此,图形前端还是 Unity,但 UI 部分完全是 Android 原生了,再也不会有因为 Unity UGUI 导致的奇怪的横屏布局问题。
之前 Unity 和 Android 对于每个功能都是单独写接口做传递,维护到后面就会有很多问题,比如状态的同步,回调的处理,异步调用因为 Unity 在后台 inactive 导致的阻塞等。因此这次使用了一个全局的 JSON 同步状态。为了避免之前为了每个属性在两边都 getter / setter 写面条代码的问题,这次在 Unity 端写了一个通过 Attribute 定义属性到 JSON 路径的映射功能,运行时在解析 JSON 后直接用反射查找属性 setter 调用,方便了很多,不过也因此选不了 il2cpp 作为 scripting backend,只能使用 mono。但其实也没什么,毕竟 il2cpp 对于我来说较为突出的优点在于 arm64 支持,但 Mapbox 的 Unity SDK 内嵌了一个 SQLite Wrapper 目前是只有 x86 和 armv7 库的,因此 arm64 显得聊胜于无。总之,stay tuned,以及希望我这次不要像之前为了一个宣传片直接跳票两个月

Unity 后期处理保证背景颜色

 • 

Unity 后期处理中如果用了 Color Grading 之类的效果器同时要保证相机背景颜色不变(比如 Unity 作为一个 View 挂在手机客户端中),就要费些功夫,因为使用多相机(一个背景相机+一个实物渲染相机)仍然是无法保证相机背景不被 depth 较高的相机上的效果器处理的,因此写了个根据相机渲染深度信息来填充特定颜色,挂在 Color Grading 后面即可。

namespace FinGameWorks.Scripts.PostProcess  
{
    using System;
    using UnityEngine;

    [RequireComponent(typeof(Camera))]
    [ExecuteInEditMode]
    public class MaskedFirstPass : MonoBehaviour
    {
        [Range(0f, 3f)] public float depthLevel = 0.5f;
        public Color backgroundColor = Color.white;

        public Shader _shader;

        private Shader shader
        {
            get { return _shader != null ? _shader : (_shader = Shader.Find("MaskedFirstPassShader")); }
        }

        private Material _material;

        private Material material
        {
            get
            {
                if (_material == null)
                {
                    _material = new Material(shader);
                    _material.hideFlags = HideFlags.HideAndDontSave;
                }

                return _material;
            }
        }

        private void Start()
        {
            if (!SystemInfo.supportsImageEffects)
            {
                print("System doesn't support image effects");
                enabled = false;
                return;
            }

            if (shader == null || !shader.isSupported)
            {
                enabled = false;
                print("Shader " + shader.name + " is not supported");
                return;
            }

            GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
        }

        private void OnDisable()
        {
            if (_material != null)
                DestroyImmediate(_material);
        }

        private void OnRenderImage(RenderTexture src, RenderTexture dest)
        {
            if (shader != null)
            {
                material.SetFloat("_DepthLevel", depthLevel);
                material.SetColor("_BGColor",backgroundColor);
                Graphics.Blit(src, dest, material);
            }
            else
            {
                Graphics.Blit(src, dest);
            }
        }
    }
}
Shader "MaskedFirstPassShader"  
{
   Properties
     {
         _BGColor ("Background Color", COLOR) = (1.0,1.0,1.0,1.0)
         _DepthLevel ("Depth Level", Range(1, 3)) = 1
         _MainTex ("Source", 2D) = "white" {}
     }
     SubShader
     {
         Pass
         {
             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag
             #include "UnityCG.cginc"

             uniform sampler2D _CameraDepthTexture;
             uniform half4 _MainTex_TexelSize;
             uniform float4 _BGColor;
             uniform fixed _DepthLevel;

             struct input
             {
                 float4 pos : POSITION;
                 half2 uv : TEXCOORD0;
             };

             struct output
             {
                 float4 pos : SV_POSITION;
                 half2 uv : TEXCOORD0;
             };

               output vert(input i)
             {
                 output o;
                 o.pos = UnityObjectToClipPos(i.pos);
                 o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, i.uv);
                 #if UNITY_UV_STARTS_AT_TOP
                 if (_MainTex_TexelSize.y < 0)
                         o.uv.y = 1 - o.uv.y;
                 #endif

                 return o;
             }

              sampler2D _MainTex;
                float4 _MainTex_ST;

             fixed4 frag(output o) : COLOR
             {
                 float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, o.uv));
                 depth = pow(Linear01Depth(depth), _DepthLevel);
                 if (depth < 0.5)
                 {
                                float4 color = tex2D(_MainTex, 
                       UnityStereoScreenSpaceUVAdjust(
                       o.uv, _MainTex_ST));    
                       return color;
                 }
                  else
                 {
                    return     _BGColor;
                 }
             }
             ENDCG
         }
     } 
}

Unity 项目打包 Framework 方式嵌入 UnityGetGLView 到 iOS 工程 (1)

 • 

距离上次写这个话题快有一年了,上次也是做外包的时候有嵌入 Unity View 到 iOS 工程的需求。这次为了双方的便捷,参考 unity-ios-framework 采用了打包整个 Unity 为静态 framework 的方法,这种方法对甲方非常友好,一次配置,以后每次只需更新 framework 和 Data 即可,而自己需要多做些配置,为了把这块也自动化,写了个 Build Script。

#!/usr/bin/env bash
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then  
source "$HOME/.rvm/scripts/rvm"  
elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then  
source "/usr/local/rvm/scripts/rvm"  
else  
printf "ERROR: An RVM installation was not found.\n"  
exit 128  
fi

# rvm default
# ruby -v
# rvm use system
# ruby -v

echo $SHELL  
which ruby  
set -e

export LANG=en_US.UTF-8  
export LANGUAGE=en_US.UTF-8  
export LC_ALL=en_US.UTF-8

if ! which ruby > /dev/null; then  
echo "error: ruby is not installed."  
exit 1  
fi

if ! which xcodeproj > /dev/null; then  
echo "error: xcodeproj 没有安装,请 [sudo] gem install xcodeproj [--user-install],如果通过 rvm 使用了其他版本 ruby 请先 rvm use system 再 install"  
exit 1  
fi

chmod u+x $SRCROOT/UnityOutFramework/UnityPreBuild.rb  
cd $SRCROOT/UnityOutFramework  
ruby UnityPreBuild.rb  

在 $SRCROOT 下面新建文件夹 UnityOutFramework,放置 Info.plist 和 UnityPreBuild.rb,内容如下

require 'xcodeproj'  
include Xcodeproj::Project::Object

puts "检查 Unity 项目所需设定"  
project_path = '../Unity-iPhone.xcodeproj'  
project = Xcodeproj::Project.open(project_path)

deleted_targets, preserved_targets = project.targets.partition{ |target| target.name == 'UnityOutFramework'}

puts 'Deleted : '  
puts deleted_targets  
puts 'Preserved : '  
puts preserved_targets

project.targets.replace(preserved_targets)

puts 'Added : '  
target = project.new_target(:framework,'UnityOutFramework',:ios)  
puts target

puts '-------- Config Names --------'  
target.build_configurations.each { |config|  
    puts config.name

    config.build_settings['HEADER_SEARCH_PATHS'] = '$(inherited) $(SRCROOT)/Classes $(SRCROOT) $(SRCROOT)/Classes/Native $(SRCROOT)/Libraries/bdwgc/include $(SRCROOT)/Libraries/libil2cpp/include'
    config.build_settings['LIBRARY_SEARCH_PATHS'] = '$(inherited) $(SRCROOT) $(SRCROOT)/Libraries'
    config.build_settings['GCC_PRECOMPILE_PREFIX_HEADER'] = 'YES'
    config.build_settings['GCC_PREFIX_HEADER'] = 'Classes/Prefix.pch'
    config.build_settings['ALWAYS_SEARCH_USER_PATHS'] = 'NO'
    config.build_settings['ARCHS'] = '$(ARCHS_STANDARD)'
    config.build_settings['INFOPLIST_FILE'] = 'UnityOutFramework/Info.plist' 
    config.build_settings['CODE_SIGN_STYLE'] = 'Automatic'
    config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.JustZht.UnityOutFramework'
    config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '8.0'
    config.build_settings['ENABLE_BITCODE'] = 'YES'
    config.build_settings['MACH_O_TYPE'] = 'staticlib'
    config.build_settings['DEFINES_MODULE'] = 'YES'
    config.build_settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu11'
    config.build_settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'YES'
    config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'gnu++14'
    config.build_settings['CLANG_CXX_LIBRARY'] = 'libc++'
    config.build_settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'YES'
    config.build_settings['CLANG_ENABLE_MODULES'] = 'YES'
    config.build_settings['CLANG_ENABLE_OBJC_ARC'] = 'YES'
    config.build_settings['CLANG_ENABLE_OBJC_WEAK'] = 'YES'
    config.build_settings['CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING'] = 'YES'
    config.build_settings['CLANG_WARN__DUPLICATE_METHOD_MATCH'] = 'YES'
    config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'YES'
    config.build_settings['GCC_THUMB_SUPPORT'] = 'NO'
    config.build_settings['GCC_USE_INDIRECT_FUNCTION_CALLS'] = 'NO'
    config.build_settings['MTL_ENABLE_DEBUG_INFO'] = 'NO'
    config.build_settings['UNITY_SCRIPTING_BACKEND'] = 'il2cpp'

    if  (config.build_settings['OTHER_CFLAGS'] == nil)
        config.build_settings['OTHER_CFLAGS'] = '$(inherited)'
    end

    if !config.build_settings['OTHER_CFLAGS'].include? "$(inherited)"
        config.build_settings['OTHER_CFLAGS'] << ' $(inherited) '
    end

    if !config.build_settings['OTHER_CFLAGS'].include? "-DRUNTIME_IL2CPP=1"
        config.build_settings['OTHER_CFLAGS'] << ' -DRUNTIME_IL2CPP=1'
    end

    # LINKER FLAGS
    if  (config.build_settings['OTHER_LDFLAGS'] == nil)
        config.build_settings['OTHER_LDFLAGS'] = '$(inherited)'
    end

    if !config.build_settings['OTHER_LDFLAGS'].include? "$(inherited)"
        config.build_settings['OTHER_LDFLAGS'] << ' $(inherited) '
    end


    if  !config.build_settings['OTHER_LDFLAGS'].include? "CoreMotion"
        config.build_settings['OTHER_LDFLAGS'] << ' -weak_framework'
        config.build_settings['OTHER_LDFLAGS'] << ' CoreMotion'
    end

    if  !config.build_settings['OTHER_LDFLAGS'].include? "-weak-lSystem"
        config.build_settings['OTHER_LDFLAGS'] << ' -weak-lSystem'
    end

    # Configs

    if config.name == 'Debug'

        if !config.build_settings['OTHER_CFLAGS'].include? "-fembed-bitcode-marker"
            config.build_settings['OTHER_CFLAGS'] << ' -fembed-bitcode-marker'
        end

    elsif config.name == 'Release' || config.name == 'ReleaseForProfiling' || config.name == 'ReleaseForRunning'

        if !config.build_settings['OTHER_CFLAGS'].include? "-fembed-bitcode"
            config.build_settings['OTHER_CFLAGS'] << ' -fembed-bitcode'
        end
    end
}

puts '-------- Build Pharses Names --------'  
target.build_phases.each { |build_phase|  
    puts build_phase.isa
    if (build_phase.isa == 'PBXSourcesBuildPhase')
            build_phase.clear 
    end
}

puts '-------- Objects Names --------'  
project.objects.each { |object|  
    puts object.display_name + ' TYPE: ' + object.isa
}

accepted_compile_sources_formats = [".cpp", ".mm", ".m"]  
unaccepted_compile_sources_file_names = ['Unity_iPhone_Tests.m','RegisterMonoModules.cpp','main.mm']

accepted_header_formats = [".h"]  
accepted_public_header_file_names = ["LifeCycleListener.h",'Preprocessor.h','RegisterFeatures.h','RenderPluginDelegate.h','UnityAppController.h','UnityForwardDecls.h','UnityInterface.h','UnityRendering.h','UnityViewControllerBase.h','UnityViewControllerBase+iOS.h']  
unaccepted_header_file_names = ['RegisterMonoModules.h']

accepted_lib_formats = [".a"]

puts '-------- Add Files --------'  
project.objects.each { |object| 

    if object.isa == 'PBXBuildFile'

        if object.file_ref.path != nil && File.extname(object.file_ref.path) != nil
            ext = File.extname(object.file_ref.path)
            fullname = File.basename(object.file_ref.path)

            if !unaccepted_compile_sources_file_names.include?(fullname) && accepted_compile_sources_formats.include?(ext)
                target.source_build_phase.add_file_reference(object.file_ref,true)
                puts 'ADDED TO COMIPLE SOURCES -> ' + object.file_ref.path
            end

            if !unaccepted_header_file_names.include?(fullname) && accepted_header_formats.include?(ext)
                is_public = false
                file = target.headers_build_phase.add_file_reference(object.file_ref,true)
                if accepted_public_header_file_names.include?(fullname)
                    file.settings = { 'ATTRIBUTES' => ['Public']}
                end
                puts 'ADDED TO HEADERS -> ' + object.file_ref.path + ' via PBXBuildFile PUBLIC -> ' + (is_public ? '1' : '0')
            end

        end

    elsif object.isa == 'PBXFileReference'

        if object.path != nil && File.extname(object.path) != nil
            ext = File.extname(object.path)
            fullname = File.basename(object.path)

            if !unaccepted_compile_sources_file_names.include?(fullname) && accepted_compile_sources_formats.include?(ext)
                target.source_build_phase.add_file_reference(object,true)
                puts 'ADDED TO COMIPLE SOURCES -> ' + object.path
            end

            if !unaccepted_header_file_names.include?(fullname) && accepted_header_formats.include?(ext)
                target.headers_build_phase.add_file_reference(object,true)
                puts 'ADDED TO HEADERS -> ' + object.path + ' via PBXFileReference'
            end

            if accepted_lib_formats.include?(ext)
                target.frameworks_build_phase.add_file_reference(object,true)
                puts 'ADDED TO FRAMEWORKS -> ' + object.path
            end
        end

    end
}

deleted_phases, preserved_phases = target.build_phases.partition{ |phase| phase.isa == 'PBXShellScriptBuildPhase' && phase.name == 'Replace Headers'}  
target.build_phases.replace(preserved_phases)  
uuid = Digest::MD5.hexdigest('Replace Headers').upcase[0,24]  
run_script_phase = PBXShellScriptBuildPhase.new(project, uuid)  
run_script_phase.initialize_defaults  
run_script_phase.name = 'Replace Headers'  
run_script_phase.shell_script = 'inputDirectory=$PROJECT_DIR/${TARGET_NAME}/FlatPathHeaders  
outputDirectory=${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/Headers

echo "in $inputDirectory"  
echo "out $outputDirectory"

if [ ! -d "$outputDirectory" ]; then  
echo "no out path,and create: $outputDirectory"  
mkdir $outputDirectory  
fi

cp -R $inputDirectory/. $outputDirectory/'  
target.build_phases.insert(target.build_phases.length, run_script_phase)

# names = [ 'Foundation', 'CoreFoundation', 'MediaPlayer', 'CoreMotion', 'MediaToolBox', 'AudioToolbox', 'AVFoundation', 'CoreMedia', 'CoreLocation' ]
# names.each do |name|
#     target.add_system_framework(name)
# end

project.save

使用时将 Run Script 添加到导出的 Xcode 项目默认 target 中(其实这块也可以直接在 Unity 内通过 PBXProject 自动添加到 target 里去),然后直接 Run。项目并不会 Run 而是会 Cancel,因为 ruby 脚本在最后保存了工程。然后就会出现 UnityOutFramework,Build 即可。

2018.6.25

 • 

朋友圈里面不停有人发毕业典礼和离校,看得我总算是有点伤感的感觉了,然而我还有一堆学校的事情要处理,去检查了次课设试验被自以为是的老师气到不行,再一回想起之前被学校各种刁难,遂又回到了对毕业没有感觉的状态。

我真正关心的是由于课程和考试的安排在第一期毕业证发放之后,估计要拖到七月初我才能拿到毕业证了。我原本打算把 WWDC 之旅当做毕业旅行,这样即使我七月才能拿到毕业证也算是已经提前放松了一段时间,如此七月二十二立刻入职腾讯也不算什么对我而言太紧迫之事。但是 WWDC 由于签证被我错过,我一下子就感觉不爽了,这样刚毕业就去工作,让我想起了前一年在百度时不太好的感觉,而我本性难改,一旦觉得自己不自由就会不停折腾,直到我自己满意为止。

刚好上次 Hackathon 有一个推荐 MSRA 的机会,虽然应该是推不进去,但是给我了一个启发就是我还是能再往上争取一把的。因此我又动了心思想再看看机会,而且如果找到厉害的新东家还能九月份入职就更好了。我和同学说了这个事情,他们笑:你都拿腾讯当保底了。我说是,我现在是拿腾讯当保底了,但是一年前这个时候我可没这个胆量,这种事情自然是走一步看一步。

然后今天去寝室拿琐碎的东西,比如活动衫,原本是毕业典礼要穿的,结果我压根就没参加毕业典礼,因此一直放在班长那里;比如优秀论文证书,也是班长帮我拿的;比如一个厚册子,貌似是给同学之间写寄语和放照片用的,我拿到之后哭笑不得,这东西看起来情真意切但放到全是手机的现在怕是留着吃灰。

不管怎样,我的大学如果考过重修就应该还差一两周就结束了。
回想一下这四年,第一年还没什么具体的头绪,后面就一直在尽力地当一个了不起的盖茨比。
我爸妈没上过大学,对于现在的大学是什么样子什么做派也并不清楚,因此在我大学中和制度摩擦的时候也没有能力提供相应的指导,比如很多和学校硬碰硬的事情其实找个人就好办很多,但是我不知道,我爸妈也没有解决的思路,因此也是我慢慢上了四年才领悟到一些事情,如果早明白一些事情,也许我会保持自己在自己喜欢做的事情上的投入,同时在学校能够做出一个好学生的样子,甚至被当做学生学和做皆优的代表,少却很多麻烦,多了很多便利。因为没上过大学,我爸妈对我完成学业有一种执念,因此在我想要退学的时候反弹比较激烈,我也答应了至少要保证大学毕业,因此好歹和学校保持着联系,偶尔在学校露一次面,以完成这个保证。临近毕业和我爸妈说后面的发展,爸妈又说要考个研究生吧。我当然是有研究生的打算的,毕竟自己也没在这个学校里学到什么真的 CS 的东西,一个是学校没教,一个是教了也厌学,那自然有很多不会的内容,需要后面上学去补,而我的计划就是工作一两年,好歹逃离学校这种地方喘息一会,等到本科 GPA 对我的影响降低之后就去申请出国看看。虽然我研究生计划是这样的,但我和爸妈说的时候总会说不确定,因为我不想到时候再保证一次了,本来上学这种事情我都快有阴影了。
爸妈的这些反应我倒也明白,也没有觉得拖累,毕竟能定义拖累的前提是能够放下,而显然我之前也说过断绝关系这种事情我是做不来的,更何况虽然看起来最近半年全靠自己挣的钱过活没花过爸妈的,但是之前也说了这种看似买买买的自由的假象是建立在有爸妈的后备基础上的,目前简单的财务状况也不是能和真正成人前瞻后顾的财务计划能比的。因此我大学中也尽力缓和家人的关系,让家人理解我看似逃学一样的事情的动机,至少不再拦着我干活,然后我再想办法找时间去改变他们。
我越是想办法往上走越是想让我的父母理解我并且帮助我,特别是最近一次 WWDC 签证的事情之后,因为我和父母都觉得如果很早之前一家人一起办十年旅游签证就不会有我现在一个人被审查的事情了,而这种事情说实话是眼界的问题,但家长的态度和眼界这是个看运气的事情,自然会有家庭出身比我所在的境遇更糟糕,比如初中的那些同学们,而我也没什么可以抱怨的,即使最后爸妈不愿意改变,那也是他们自己的事情,但我至少要去尝试罢了。

大学最后一次课程设计检查

 • 

写了个项目去检查
我:老师我大四的,请问能不能这节课检查下,然后早点登记分数
老师:我是不可能给你一个人登记分数的,你要等大家都结束才行
我:那老师能不能先提前检查下,毕竟我也大四了
老师:不行,大四唯一的例外是有几个外语院的同学要回家了所以提前检查
我:但是昨天毕业典礼后大家都可以回家了,所以老师我也是想着能不能早点结束
老师:那你检查最多只能及格
我:好的好的
(老师翻点名册没找到我)
老师:你不是大四的吗,我这里只有一五级一六级的,你是怎么进来的?
(我同学帮我指了下我在花名册里面的位置)
老师看了下花名册里面的签到表:看你三次课里面两次都没来,你可以不用检查了(意指我可以挂科了)
我:老师我第一次和您在 QQ 上请假了,当时我和您说要去办签证参加 WWDC,第二次就是今天您刚才下午点名的时候我在改代码。
老师:行吧你给我看看你的东西
(看完我的项目)
老师:你刚才我只准备给你个及格,但是我听你讲了之后可以给你个中等
我:谢谢老师

大学其他对话系列:辅导员 | 软件外包赛校内答辩经过

2018.6.13

 • 

昨天签证 issue 了。还没寄回来,不过估计是一年签。虽然 WWDC 都结束了,不过考虑着今年还是要去美国一趟(比如找 Cee 玩),就是不知今年内还有没有大片的空闲时间。
答辩论文申请了校级本科优秀论文,最后拿了二等。总共有一等,二等,优秀三个等级,学院内三个等级加起来有 20 人。也不清楚具体是什么水平,反正我妈应该会高兴点,毕竟我大学四年没怎么给她拿过学校内部的荣誉,好不容易临毕业了有个学校认证的东西。
还有三门考试,目前事情一堆还没复习,也不轻松。不过因为学校人事带来的关于体测的乱七八糟的事情总算是过去了。
Golf GO (Scholarship Edition) 和由 Lonely Planet 改名后重新提交的 Epoch Core 都上架了。

2018.6.7

 • 

我的签证果然没有在武汉飞旧金山的航班飞走前结束审查。我发了十几封催签邮件,给 DOS 打了几次电话,甚至想着如果 WWDC 开幕式前一天签证下来了我就直接定北京到圣何塞的机票还能赶得上发布会,结果也没发生。
所以这就是我大学的第一个 WWDC 奖学金,也是最后一个,也是压根就没去成的一个。有点无奈,但也没办法。去不成自然会错过很多机会,少面基很多人,但是这个世界又不是绕着我转的,而且我还有其他事情不得不忙。
五月份筹备 WWDC 的行程时发现和毕设答辩撞了车,结果导师人很好让我可以提前答辩,因此提前准备了很多东西,结果签证没有如期发下来,最后我还是跟着大家一起正常答辩,也就是昨天下午。对别人来说答辩完就是大学结束了,对于我来说还有三门要考的试。啊不管怎么样算是告一段落,等真正毕业后估计还要写四年的所见,暂先不表。


五月底又打了把 hackathon,湖南大学办的华中 HHHackathon。和李霖及李霖的女朋友组队,基于 CoreML 和 ARKit 弄了个简单的三维维基百科,最后拿了第二和京东单项奖。
作为一个好歹在国内 hackathon 组队拿过六七次前三名的半职业打手(误),我觉得还是有点资格评判下湖大这次的组织和流程的。总而言之,湖大是把 hackathon 当成校赛来办。
校赛意味着两件事:第一是学校牵扯其中,自然会有很多学校的特殊规定,如不让人擅自离场吃饭(只能吃会场内的盒饭),不让人回宿舍睡觉,当然这些是出于学校对安全的一些硬性要求,情理上也能理解,但如果外加场地条件很差就是个灾难了,本身第一次办 hackathon 的组织都会对网络估计不足,这次也一样,外加晚上强制让睡会场,还好我们队不管规则纪律晚上照样回自己家休息了(毕竟不是湖大的学生,也处分不到我们头上),不然估计要和其他人一样在会场喂蚊子。这第二呢,就是校赛自然有很多说不清道不明的东西,比如有的队伍提前一周就开始开发了,主持人还说既然题目有公布,这种事情自然是允许的;比如有的队伍自带湖大的带队老师;比如大部分队伍的实现程度都没有到代码的程度,然后看到了熟悉的墨刀流(做个原型说自己有成品之流);比如赛后的官方新闻稿全篇都在说第一和第三名两个湖大的项目,第二名反正不是湖大的一笔带过,这对于学校宣传来说自然是无可厚非的,但既然是 hackathon 基本的平台中立还是要有的,学校可以单独发新闻稿,但是把参赛的包括武汉和南京远道而来的大家都裹挟到一篇只提到湖大自己的文章里面一笔带过就有些让我不太爽了,不过考虑到这个比赛也许就是按照校内比赛来办的,倒也是能说得通。只是我不太喜欢吧,毕竟这次比赛可是套着 hackathon 的头衔,然而只学到了 24 小时现场编程这个规定,而没学到真正让 hackathon 成为 hackathon 的东西,总让我们这些人感觉是到贵校“万国来朝”的,仅此而已
写完觉得还是说的有点刻薄了,毕竟话说吃别人的嘴软,但事实也就我描述的这样,外加我的确很反感校赛,这个不满的情绪怕是从大一就开始积攒了。我讨厌各种华而不实的校赛,讨厌各种吹上天的 PPT 和 BP,讨厌拿墨刀原型当成品,讨厌校内带队老师和评委之间说不清的照顾,讨厌纯学生组队没有带队老师的无力感,就这样


我把 Cetacea 开源了。实在是没精力折腾下去了,之前选用的 Bundle Based NSDocument,正则做 MD 解析外加 iCloud 的方案现在看起来有点蠢,不如等后面从头写一个基于 CMark,不管文件同步而是纯编辑器的小项目,再慢慢拓展,不然对于这种较大的 macOS 项目我现在仍然没有足够的能力去理清头绪,更别提两年前开始这个项目的时候了。

然后 Lonely Planet 被出版社发邮件说商标侵权后我自己 take down 了相关的各种东西,包括上架了的软件和相关视频,这几天估计会以 Epoch Core 的名字重新上线,内容还是一年前的 Epoch Core,而最近在 Epoch 上取得的进展估计要到七月底才有时间往 Core 里面整理了。

接下来就是 Skyline。因为毕设和之前一个一言难进的外包,Skyline 推迟了很多次更新,最近会关注下了。基于 Unity 2018.1 轻量级渲染管道和 Marklight 实现 UI 的版本估计会在六月底发包,然后等 Unity 出纯 ECS 的超小引擎包(参见 Unity at GDC - ECS for Small Things)的时候我再迁移上去,但是 Mapbox 的 C# SDK 还不知道会什么时候迁移到基于 ECS 的架构上去(说到这个他们公司之前和我接触了下但是我貌似忘了回邮件了 -。-),因此要这么做的话我还要自己写一个基本的请求层实现,那么要做的工作和我基于 LibGDX 重写的 Skyline GO 已经差不多了。总而言之,一个因为一开始脑抽用了 Unity + Android 的混合架构所以我目前还是不太想碰的老 code base,和目前还是烂摊子的重写计划,哪一个都不是个容易的事情。但我总觉得不能赚了一笔就跑路,虽然我事实上估计已经是了(


买了个 iPod Classic 6th gen,塞了很多音乐进去。最近听了 Soulection Radio Tour - Live at the El Rey Soulection Radio Show #343Coral City | Vol. 1Road TripBack to Life,此外看了一个有趣的视频 Evolution Simulator