添加新的fc模拟器页面

This commit is contained in:
zhl 2019-06-11 15:27:11 +08:00
parent 21c74e2c35
commit fff6b7653d
41 changed files with 16312 additions and 129 deletions

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

686
fc2/css/fc.css Normal file
View File

@ -0,0 +1,686 @@
@charset "utf-8";
a,mark {
color:inherit
}
html {
color:#000;
background:#fff;
font-family:Arial,'Microsoft YaHei';
font-size:34px;
-webkit-user-select:none;
user-select:none;
-webkit-overflow-scrolling:touch
}
body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,strong,td,textarea,th,ul {
padding:0;
margin:0
}
table {
border-collapse:collapse;
border-spacing:0
}
img {
display:block;
border:0;
max-width:100%
}
a {
text-decoration:none;
outline:0
}
em,i,strong {
font-style:inherit;
font-weight:inherit
}
li {
list-style:none
}
h1,h2,h3,h4,h5,h6 {
font-size:100%;
font-weight:400
}
button,input,optgroup,option,select,textarea {
font-family:inherit;
font-size:inherit;
font-style:inherit;
font-weight:inherit
}
mark {
background-color:rgba(0,0,0,0)
}
.clearfix:after {
content:"\200B";
display:block;
height:0;
clear:both
}
.none,[v-cloak] {
display:none
}
.dire-wrap,.key-wrap {
display:inline-block;
overflow:hidden;
will-change:auto;
contain:style;
backface-visibility:hidden
}
.mask {
position:fixed;
width:100%;
height:100%;
left:0;
top:0;
z-index:95;
background:rgba(0,0,0,.7)
}
.tx_ov {
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis
}
.tx_wrap {
word-break:break-all;
word-wrap:break-word
}
body {
background:#000
}
.dc-centre,.dc-dire,.dire-ctrl,.key-btn {
background-size:100% 100%
}
#screen {
position:absolute;
width:256px;
height:240px;
top:calc((100vh + 50px - 256px)/ 2);
right: 240px;
transform:scale(3.3333,3.3333) rotate(90deg);
border:none;
overflow:hidden
}
.ctrl-wrap {
position:fixed;
height:100vh;
width:100%;
top:0;
left:0
}
.dc-centre,.dc-dire,.dire-ctrl,.dire-wrap,.key-btn,.key-wrap {
position:absolute
}
.dire-wrap {
width:390px;
height:390px;
top:-10px;
left:-10px
}
.dire-ctrl {
width:290px;
height:290px;
margin:50px;
background-image:url(../images/7.png);
overflow:hidden
}
.dc-centre {
width:124px;
height:124px;
background-image:url(../images/8.png);
will-change:auto;
contain:style
}
.dc-dire {
width:384px;
height:384px;
margin:3px;
background-image:url(../images/9.png);
will-change:auto;
contain:style
}
.key-wrap {
width:100vw;
height:390px;
bottom:20px;
left:20px
}
.key-btn {
width:150px;
height:150px;
line-height:150px;
text-align:center;
font-size:56px;
transform:rotate(90deg);
font-weight:700;
color:rgba(255,255,255,.5);
opacity:.5;
background-image:url(../images/8.png)
}
.key-btn.kay-B {
top:88px;
left:90px;
opacity:.7
}
.key-btn.kay-A {
top:220px;
left:0px;
opacity:.7
}
.key-btn.kay-Y {
top:88px;
left:232px
}
.key-btn.kay-X {
top:256px;
left:162px
}
.key-btn.kay-AB {
top:220px;
left:222px
}
.key-btn.flat-btn {
width:120px;
height:80px;
font-size:30px;
line-height:80px
}
.key-btn.kay-SE {
top:120px;
right:60px
}
.key-btn.kay-ST {
top:260px;
right:60px
}
.btn-on {
transform:scale(.9,.9) rotate(90deg)
}
.layui-m-layer {
position:relative;
z-index:19891014
}
.layui-m-layer * {
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box
}
.layui-m-layermain,.layui-m-layershade {
position:fixed;
left:0;
top:0;
width:100%;
height:100%
}
.layui-m-layershade {
background-color:rgba(0,0,0,.7);
pointer-events:auto
}
.layui-m-layermain {
display:table;
pointer-events:none
}
.layui-m-layermain .layui-m-layersection {
display:table-cell;
vertical-align:middle;
text-align:center
}
.layui-m-layerchild {
position:relative;
display:inline-block;
text-align:left;
background-color:#fff;
font-size:2.6vh;
border-radius:20px;
box-shadow:0 0 8px rgba(0,0,0,.1);
pointer-events:auto;
-webkit-overflow-scrolling:touch;
-webkit-animation-fill-mode:both;
animation-fill-mode:both;
-webkit-animation-duration:.2s;
animation-duration:.2s
}
@-webkit-keyframes layui-m-anim-scale {
0% {
opacity:0;
-webkit-transform:scale(.5);
transform:scale(.5)
}
100% {
opacity:1;
-webkit-transform:scale(1);
transform:scale(1)
}
}@keyframes layui-m-anim-scale {
0% {
opacity:0;
-webkit-transform:scale(.5);
transform:scale(.5)
}
100% {
opacity:1;
-webkit-transform:scale(1);
transform:scale(1)
}
}.layui-m-anim-scale {
animation-name:layui-m-anim-scale;
-webkit-animation-name:layui-m-anim-scale
}
@-webkit-keyframes layui-m-anim-up {
0% {
opacity:0;
-webkit-transform:translateY(1600px);
transform:translateY(1600px)
}
100% {
opacity:1;
-webkit-transform:translateY(0);
transform:translateY(0)
}
}@keyframes layui-m-anim-up {
0% {
opacity:0;
-webkit-transform:translateY(1600px);
transform:translateY(1600px)
}
100% {
opacity:1;
-webkit-transform:translateY(0);
transform:translateY(0)
}
}.layui-m-anim-up {
-webkit-animation-name:layui-m-anim-up;
animation-name:layui-m-anim-up
}
.layui-m-layer0 .layui-m-layerchild {
width:70%
}
.layui-m-layer1 .layui-m-layerchild {
border:none;
border-radius:0
}
.layui-m-layer2 .layui-m-layerchild {
width:15vh;
border:none;
padding:35px 0;
box-shadow:none;
color:#fff;
background-color:rgba(0,0,0,.7)
}
.layui-m-layerchild h3 {
padding:0 5%;
height:7.5vh;
line-height:7.5vh;
font-size:2.8vh;
font-weight:400;
border-radius:20px 20px 0 0;
text-align:center;
border-bottom:1px solid #E0E0E0
}
.layui-m-layerbtn span,.layui-m-layerchild h3 {
text-overflow:ellipsis;
overflow:hidden;
white-space:nowrap
}
.layui-m-layercont {
padding:8% 10%;
line-height:4vh;
text-align:center
}
.layui-m-layer1 .layui-m-layercont {
padding:0;
text-align:left
}
.layui-m-layer2 .layui-m-layercont {
text-align:center;
padding:0;
line-height:0
}
.layui-m-layer2 .layui-m-layercont i {
width:3vh;
height:3vh;
margin-left:1vh;
display:inline-block;
background-color:#fff;
border-radius:100%;
-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;
animation:layui-m-anim-loading 1.4s infinite ease-in-out;
-webkit-animation-fill-mode:both;
animation-fill-mode:both
}
.layui-m-layerbtn,.layui-m-layerbtn span {
position:relative;
text-align:center;
border-radius:0 0 20px 20px
}
.layui-m-layer2 .layui-m-layercont p {
margin-top:2vh;
font-size:2.5vh
}
@-webkit-keyframes layui-m-anim-loading {
0%,100%,80% {
transform:scale(0);
-webkit-transform:scale(0)
}
40% {
transform:scale(1);
-webkit-transform:scale(1)
}
}@keyframes layui-m-anim-loading {
0%,100%,80% {
transform:scale(0);
-webkit-transform:scale(0)
}
40% {
transform:scale(1);
-webkit-transform:scale(1)
}
}.layui-m-layer2 .layui-m-layercont i:first-child {
margin-left:0;
-webkit-animation-delay:-.32s;
animation-delay:-.32s
}
.layui-m-layer2 .layui-m-layercont i.layui-m-layerload {
-webkit-animation-delay:-.16s;
animation-delay:-.16s
}
.layui-m-layer2 .layui-m-layercont>div {
line-height:3.3vh;
padding-top:14px;
margin-bottom:40px;
font-size:3vh
}
.layui-m-layerbtn {
display:block;
display:-moz-box;
display:-webkit-box;
width:100%;
height:7.5vh;
line-height:7.5vh;
font-size:0;
border-top:1px solid #ddd;
background-color:#FFF
}
.layui-m-layerbtn span {
display:block;
-moz-box-flex:1;
box-flex:1;
-webkit-box-flex:1;
font-size:2.8vh;
cursor:pointer;
color:#0084ff
}
.layui-m-layerbtn span[yes] {
border-radius:0 0 20px
}
.layui-m-layerbtn span[no] {
border-right:1px solid #ddd;
border-radius:0 0 0 20px
}
.layui-m-layerbtn span:active {
background-color:#F6F6F6
}
.layui-m-layerend {
position:absolute;
right:14px;
top:20px;
width:60px;
height:60px;
border:0;
font-weight:400;
background:0 0;
cursor:pointer;
-webkit-appearance:none;
font-size:6vh
}
.layui-m-layerend::after,.layui-m-layerend::before {
position:absolute;
left:10px;
top:30px;
content:'';
width:18px;
height:1px;
background-color:#999;
transform:rotate(45deg);
-webkit-transform:rotate(45deg);
border-radius:12px
}
.layui-m-layerend::after {
transform:rotate(-45deg);
-webkit-transform:rotate(-45deg)
}
body .layui-m-layer .layui-m-layer-footer {
position:fixed;
width:95%;
max-width:100%;
margin:0 auto;
left:0;
right:0;
bottom:20px;
background:0 0
}
.layui-m-layer-footer .layui-m-layercont {
padding:20px;
border-radius:20px 20px 0 0;
background-color:rgba(255,255,255,.8)
}
.layui-m-layer-footer .layui-m-layerbtn {
display:block;
height:auto;
background:0 0;
border-top:none
}
.layui-m-layer-footer .layui-m-layerbtn span {
background-color:rgba(255,255,255,.8)
}
.layui-m-layer-footer .layui-m-layerbtn span[no] {
color:#FD482C;
border-top:1px solid #c2c2c2;
border-radius:0 0 20px 20px
}
.layui-m-layer-footer .layui-m-layerbtn span[yes] {
margin-top:20px;
border-radius:20px
}
body .layui-m-layer .layui-m-layer-msg {
width:auto;
max-width:90%;
margin:0 auto;
background-color:rgba(0,0,0,.7);
color:#fff
}
.layui-m-layer-msg .layui-m-layercont {
padding:20px 40px;
font-size:2.8vh
}
/*html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
cursor: none;
}
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}*/
/*span {
color: red;
bottom: 0px;
position: absolute;
right: 0px;
display: none;
font-size: 40pt;
font-weight: bold;
text-align: right;
vertical-align: bottom;
font-family: monospace;
display:none;
}*/
.background-div{
position: fixed;
background-color: #000;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.info-mask {
position: absolute;
top: 0;
left: 0;
width: 110vw;
height: 250vw;
background-color: #000;
overflow-x: hidden;
overflow-y: auto;
background-image:url(../images/invite-mask.jpg);
background-repeat:no-repeat;
background-size: 100%
}
#mask-img {
width: 100%;
height: 100%;
opacity: 0;
}
.container::-webkit-scrollbar {
display: none;
}
.real .dire-ctrl {
background-image:url(../images/rocker.png);
}
.real .dc-centre {
display: none;
}
.real .dc-dire {
background-image:url(../images/direct-shadow.png);
}
.real .direct-wrap {
display: grid;
}
.direct-btn {
}
.real .key-btn {
opacity:1!important;
background-image:url(../images/button.png)!important;
}
.real .flat-btn {
background-image:url(../images/flat-button.png)!important;;
opacity:.7!important;;
width:150px!important;
}
.real .kay-SE {
top:100px!important;
}
.real .kay-ST {
right:60px!important;;
}
.hidden {
display: none!important;
}
.menu-back {
background-color: #000;
opacity: 0.5;
position: absolute;
left: 0;
top: 0;
bottom: 0;
right:0;
display: none;
}
.menu-container {
background-color: white;
width: 100vw;
height: 60vw;
position: absolute;
left: 50%;
top: 50%;
margin-left: -50vw;
margin-top: -30vw;
transform: rotate(90deg);
display: flex;
flex-direction: column;
border-radius: 10px;
}
.menu-container .menu-title {
height: 80px;
padding: 10px 30px;
display: flex;
align-items: center;
color: #777;
}
.menu-container .menu-body {
flex: 1;
padding: 10px;
}
.menu-body .row {
margin-left: 5px;
margin-right: 5px;
padding: 15px;
margin-bottom: 5px;
display: flex;
}
.menu-body .row .row-title {
width: 30%;
color: #777;
}
.menu-body .row .row-body {
flex: 1;
display: flex;
}
.row-body .row-part{
width: 50%;
}
.row-part input[type='radio']{
width: 30px;
height: 30px;
margin-right: 10px;
}
.menu-container .menu-footer {
height: 80px;
display: flex;
}
.menu-container .menu-footer .left-part {
flex:1;
}
.menu-container .menu-footer .right-part {
display: flex;
padding: 5px 20px;
}
.menu-container .menu-footer .menu-btn {
width: 100px;
height: 50px;
text-align: center;
border: 1px solid #ddd;
margin-right: 10px;
padding: 4px 10px;
border-radius: 4px;
}
.menu-btn.btn-success{
color: #fff;
background-color: #449d44;
border-color: #398439;
}
#menu_btn{
top: 120px;
right: 60px;
width: 120px;
height: 80px;
font-size: 30px;
line-height: 80px;
text-align: center;
transform: rotate(90deg);
font-weight: 700;
color: rgba(255,255,255,.5);
opacity: .5;
position: absolute;
background-size: 100% 100%;
background-image: url(../images/8.png);
z-index: 10;
}
#menu_btn.real{
background-image: url(../images/flat-button.png);
}

BIN
fc2/images/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
fc2/images/8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
fc2/images/9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
fc2/images/button-press.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
fc2/images/button.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
fc2/images/flat-button.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
fc2/images/invite-mask.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

372
fc2/images/kingsomevs.proto Normal file
View File

@ -0,0 +1,372 @@
//syntax = "proto2";
package kingsomevs;
/*
CM前缀(client message)
SM前缀(server message)
MF前缀send(message field)
custom_data:
_e后缀
msghead + msgbody
msghead: packagelen + msgid + magiccode = 2 + 2 + 4 = 8
msgbody protobuf数据
msghead说明
packagelenunsigned short
msgid(unsigned short): id
magiccode(unsigned int): 40xAABBCCAA
*/
//
message MFOptResult
{
optional int32 error_code = 1; //
optional string error_msg = 2; //
optional string debug_msg = 3; //
}
//
message MFRoomUserInfo
{
optional string account_id = 1; //id
optional string user_profile = 2; //
optional int32 user_idx = 3; //
}
//
message MFRoomRobotInfo
{
optional string robot_uniid = 1; //id
optional string robot_name = 2; //
optional string avatar_url = 3; //
}
//
message MFRoomEventInfo
{
optional string custom_data = 1; //
optional string src_account_id = 2; //id
}
//
message MFRoomInfo
{
optional string room_id = 1; //
optional string owner_id = 2; //ID
optional string room_property = 3; //
optional int32 _timestamp = 4; //
optional int32 create_time = 5; //
optional int32 max_player = 6; //
optional int32 allow_merge = 7 [default = 0]; // 0: 1:
repeated MFRoomRobotInfo robot_list = 8; // size() == max_player
optional int32 started = 9; //0 1:
optional int32 reset_count = 10; // 0++
optional int32 join_over = 11; //0 1:
optional int32 auto_exit_room = 12; //退 0:退() 1退
}
//
message MFCreateRoomInfo
{
optional string room_name = 1; //
optional int32 max_player = 2; //
optional int32 allow_merge = 3 [default = 0]; // 0: 1:
optional int32 auto_exit_room = 4; //退 0:退() 1退
}
//
message MFFrameItem
{
optional string src_account_id = 1; //id
optional string custom_data = 2; //
optional double timestamp = 3; //
}
//
message MFFrameEventInfo
{
optional int32 frame_index = 1; //
repeated MFFrameItem frame_items = 2; //
optional int32 frame_wait_count = 3; //
}
//-------------------------mfxxx end---------------------------------------
//
message CMLogin
{
optional string account_id = 1; //id
optional string session_id = 2; //session_id
optional string game_id = 3; //game_id
optional string device_id = 4; //device_id
}
message SMLogin
{
optional MFOptResult result = 1; //error_code 0: -1:
optional string room_id = 2; //id
}
//
message CMPing
{
}
message SMPing
{
}
//
message CMCreateRoom
{
optional MFCreateRoomInfo create_room_info = 1; //
optional string user_profile = 2; //
}
message SMCreateRoom
{
optional MFOptResult result = 1; //error_code 0: -1: -2: -3: -4
optional string room_id = 2; //id
optional int32 create_time = 5; //
optional MFRoomInfo room_info = 6; //
}
//
message CMJoinRandomRoom
{
optional int32 max_player = 1; //
optional string user_profile = 2; //
}
message SMJoinRandomRoom
{
optional MFOptResult result = 1; //error_code 0: -3: -4
optional MFRoomInfo room_info = 2; //
repeated MFRoomUserInfo room_user_info_list = 3; //
}
//
message CMJoinRoom
{
optional string room_id = 1; //id
optional string user_profile = 2; //
}
message SMJoinRoom
{
optional MFOptResult result = 1; //error_code 0: -1: id不存在 -2: -3: -4 -5
optional MFRoomInfo room_info = 2; //
repeated MFRoomUserInfo room_user_info_list = 3; //
}
//
message SMRoomPeerJoinNotify
{
optional MFRoomUserInfo room_user_info = 1; //
}
//
message CMKickPlayer
{
optional string account_id = 1; //id
optional string custom_data = 2; //
}
message SMKickPlayer
{
optional MFOptResult result = 1; //error_code 0: -1:
optional string account_id = 2; //id
optional string custom_data = 3; //
}
//notify
message SMRoomKickPlayerNotify
{
optional string account_id = 1; //id
optional string custom_data = 2; //
optional string owner_id = 3; //
}
//
message CMJoinOver
{
optional string custom_data = 1; //
}
message SMJoinOver
{
optional MFOptResult result = 1; //
optional string custom_data = 2; //
}
//notify
message SMJoinOverNotify
{
optional string custom_data = 1; //
}
//
message CMJoinOpen
{
optional string custom_data = 1; //
}
message SMJoinOpen
{
optional MFOptResult result = 1; //
optional string custom_data = 2; //
}
//notify
message SMJoinOpenNotify
{
optional string custom_data = 1; //
}
//
message CMGameStart
{
optional string custom_data = 1; //
}
message SMGameStart
{
optional MFOptResult result = 1; //
optional string custom_data = 2; //
}
//
message CMSendRoomEvent
{
optional string custom_data = 1; //
}
message SMSendRoomEvent
{
optional MFOptResult result = 1; //
optional string event_id = 2; //id
optional string custom_data = 3; //
optional int32 _timestamp = 4; //
}
//
message SMRoomEventNotify
{
optional string src_account_id = 1; //id
optional string event_id = 2; //id
optional string custom_data = 3; //
optional int32 _timestamp = 4; //
}
//
message CMLeaveRoom
{
optional string custom_data = 1; //
}
message SMLeaveRoom
{
optional MFOptResult result = 1; //error_code 0: -1:
optional string room_id = 2; //id
optional string account_id = 3; //id
optional string custom_data = 4; //
}
//
message CMSetRoomParam
{
optional int32 allow_merge = 1 [default = 0]; // 0: 1:
}
message SMSetRoomParam
{
optional MFOptResult result = 1; //error_code 0:
}
// started
//0
message CMResetRoom
{
optional int32 join_over = 1; // 0: 1:
}
message SMResetRoom
{
optional MFOptResult result = 1; //error_code 0:
}
//退matchvs sdk层实现,
//CMForceExitRoom消息退上一个房间
message CMForceExitRoom
{
optional string room_id = 1; //id
}
//
message SMRoomPeerLeaveNotify
{
optional string room_id = 1; //id
optional MFRoomUserInfo room_user_info = 2; //
optional int32 reason = 3; //0:退 1:线退(auto_exit_room) 2:CMForceExitRoom
}
//
message CMSetFrameSync
{
optional int32 frame_rate = 1; //
}
message SMSetFrameSync
{
optional MFOptResult result = 1; //error_code 0: -1: frame_rate大于30
optional int32 frame_rate = 2; //
}
//
message CMSendFrameEvent
{
optional string custom_data = 1; //
}
message SMSendFrameEvent
{
optional MFOptResult result = 1; //
}
//线
message CMReConnect
{
optional string room_id = 1; //
optional string account_id = 2; //id
optional string session_id = 3; //session_id
}
message SMReConnect
{
optional MFOptResult result = 1; //error_code 0: -1:session已失效 -2: -3
optional MFRoomInfo room_info = 2; //
repeated MFRoomUserInfo room_user_info_list = 3; //
}
//
//
message SMFrameEventUpdateNotify
{
optional MFFrameEventInfo frame_info = 1; //
}
//
message SMRoomDisbandNotify
{
optional string room_id = 1; //id
}
// source target
message SMRoomMergeNotify
{
optional string source_room_id = 1; //id
optional MFRoomInfo target_room_info = 2; //
repeated MFRoomUserInfo target_room_user_info_list = 3; //
}
//
message SMRoomResetNotify
{
optional MFRoomInfo room_info = 1; //
repeated MFRoomUserInfo room_user_info_list = 2; //
}
//
message SMNetWorkStateNotify
{
optional string room_id = 1; //id
optional string account_id = 2; //
optional int32 state = 3; // 1- 2- 3-退
optional string owner = 4; //id
}

66
fc2/images/messages.proto Normal file
View File

@ -0,0 +1,66 @@
//syntax = "proto2";
package kingsomevs;
//id定义
enum CMMessageId_e
{
_CMBegin_ = 1;
_CMPing = 50;
_CMLogin = 100;
_CMCreateRoom = 101;
_CMJoinRandomRoom = 102;
_CMJoinRoom = 103;
_CMKickPlayer = 104;
_CMJoinOver = 105;
_CMJoinOpen = 106;
_CMGameStart = 107;
_CMSendRoomEvent = 108;
_CMLeaveRoom = 109;
_CMSetRoomParam = 110;
_CMResetRoom = 111;
_CMForceExitRoom = 112;
_CMSetFrameSync = 120;
_CMSendFrameEvent = 121;
_CMReConnect = 130;
_CMEnd_ = 2000;
}
enum SMMessageId_e
{
_SMBegin_ = 1;
_SMPing = 50;
_SMLogin = 100;
_SMCreateRoom = 101;
_SMJoinRandomRoom = 102;
_SMJoinRoom = 103;
_SMKickPlayer = 104;
_SMJoinOver = 105;
_SMJoinOpen = 106;
_SMGameStart = 107;
_SMSendRoomEvent = 108;
_SMLeaveRoom = 109;
_SMSetRoomParam = 110;
_SMResetRoom = 111;
_SMSetFrameSync = 120;
_SMSendFrameEvent = 121;
_SMReConnect = 130;
_SMRoomPeerJoinNotify = 200;
_SMRoomKickPlayerNotify = 201;
_SMRoomEventNotify = 202;
_SMRoomPeerLeaveNotify = 203;
_SMRoomDisbandNotify = 204;
_SMJoinOverNotify = 205;
_SMJoinOpenNotify = 206;
_SMRoomMergeNotify = 207;
_SMRoomResetNotify = 208;
_SMFrameEventUpdateNotify = 210;
_SMNetWorkStateNotify = 220;
_SMEnd_ = 2000;
}

BIN
fc2/images/rocker-down.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
fc2/images/rocker-left.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
fc2/images/rocker-up.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
fc2/images/rocker.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
fc2/images/rockerLeftDown.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
fc2/images/rockerLeftUp.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

67
fc2/index.html Normal file
View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta name="format-detection" content="telephone=no">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=750,minimum-scale=0.4,maximum-scale=1,user-scalable=no">
<title></title>
<link href="css/fc.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/pako.js"></script>
<script type="text/javascript" src="js/nes-embed.js"></script>
<script type="text/javascript" src="js/nes-worker.js"></script>
<script type="text/javascript" src="js/js.cookie.js"></script>
<script type="text/javascript" src="js/options.js"></script>
</head>
<body>
<div>
<div id="emulator"></div>
</div>
<div class='background-div'></div>
<canvas id="screen" width="256" height="240"></canvas>
<div class="" id="menu_btn">选项</div>
<div id="ctrl-wrap" class="ctrl-wrap real">
<div class="dire-wrap">
<div class="dire-ctrl">
<div class="dc-centre"></div>
</div>
<div class="dc-dire"></div>
</div>
<div class="key-wrap">
<div class="key-btn kay-A" data-key="A">A</div>
<div class="key-btn kay-B" data-key="B">B</div>
<div class="key-btn kay-AB" data-key="AB">AB</div>
<div class="key-btn kay-SE flat-btn" data-key="SE">选择</div>
<div class="key-btn kay-ST flat-btn" data-key="ST">开始</div>
</div>
</div>
<div class='info-mask' id='info-mask' style="display: none;"></div>
<div class="menu-back" id="menu_back">
</div>
<div class="menu-container hidden" id="menu_container">
<div class="menu-title">选项</div>
<div class="menu-body">
<div class="row">
<div class="row-title">按键类型</div>
<div class="row-body">
<div class="row-part">
<input type="radio" value="O" id="radio0" name="key_type" class="md-radiobtn">摇杆
</div>
<div class="row-part">
<input type="radio" value="N" id="radio1" name="key_type" class="md-radiobtn">按键
</div>
</div>
</div>
</div>
<div class="menu-footer">
<div class="left-part"></div>
<div class="right-part">
<div class="menu-btn" id="cancel_btn">取消</div>
<div class="menu-btn btn-success" id="save_btn">确定</div>
</div>
</div>
</div>
</body>
</html>

2
fc2/js/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

163
fc2/js/js.cookie.js Normal file
View File

@ -0,0 +1,163 @@
/*!
* JavaScript Cookie v2.2.0
* https://github.com/js-cookie/js-cookie
*
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
* Released under the MIT license
*/
;(function (factory) {
var registeredInModuleLoader;
if (typeof define === 'function' && define.amd) {
define(factory);
registeredInModuleLoader = true;
}
if (typeof exports === 'object') {
module.exports = factory();
registeredInModuleLoader = true;
}
if (!registeredInModuleLoader) {
var OldCookies = window.Cookies;
var api = window.Cookies = factory();
api.noConflict = function () {
window.Cookies = OldCookies;
return api;
};
}
}(function () {
function extend () {
var i = 0;
var result = {};
for (; i < arguments.length; i++) {
var attributes = arguments[ i ];
for (var key in attributes) {
result[key] = attributes[key];
}
}
return result;
}
function decode (s) {
return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
}
function init (converter) {
function api() {}
function set (key, value, attributes) {
if (typeof document === 'undefined') {
return;
}
attributes = extend({
path: '/'
}, api.defaults, attributes);
if (typeof attributes.expires === 'number') {
attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
}
// We're using "expires" because "max-age" is not supported by IE
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
try {
var result = JSON.stringify(value);
if (/^[\{\[]/.test(result)) {
value = result;
}
} catch (e) {}
value = converter.write ?
converter.write(value, key) :
encodeURIComponent(String(value))
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
key = encodeURIComponent(String(key))
.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
.replace(/[\(\)]/g, escape);
var stringifiedAttributes = '';
for (var attributeName in attributes) {
if (!attributes[attributeName]) {
continue;
}
stringifiedAttributes += '; ' + attributeName;
if (attributes[attributeName] === true) {
continue;
}
// Considers RFC 6265 section 5.2:
// ...
// 3. If the remaining unparsed-attributes contains a %x3B (";")
// character:
// Consume the characters of the unparsed-attributes up to,
// not including, the first %x3B (";") character.
// ...
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
}
return (document.cookie = key + '=' + value + stringifiedAttributes);
}
function get (key, json) {
if (typeof document === 'undefined') {
return;
}
var jar = {};
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all.
var cookies = document.cookie ? document.cookie.split('; ') : [];
var i = 0;
for (; i < cookies.length; i++) {
var parts = cookies[i].split('=');
var cookie = parts.slice(1).join('=');
if (!json && cookie.charAt(0) === '"') {
cookie = cookie.slice(1, -1);
}
try {
var name = decode(parts[0]);
cookie = (converter.read || converter)(cookie, name) ||
decode(cookie);
if (json) {
try {
cookie = JSON.parse(cookie);
} catch (e) {}
}
jar[name] = cookie;
if (key === name) {
break;
}
} catch (e) {}
}
return key ? jar[key] : jar;
}
api.set = set;
api.get = function (key) {
return get(key, false /* read as raw */);
};
api.getJSON = function (key) {
return get(key, true /* read as json */);
};
api.remove = function (key, attributes) {
set(key, '', extend(attributes, {
expires: -1
}));
};
api.defaults = {};
api.withConverter = init;
return api;
}
return init(function () {});
}));

2
fc2/js/jsnes.min.js vendored Normal file

File diff suppressed because one or more lines are too long

373
fc2/js/nes-embed.js Normal file
View File

@ -0,0 +1,373 @@
var SCREEN_WIDTH = 256;
var SCREEN_HEIGHT = 240;
var canvas_ctx, image;
var framebuffer_u8, framebuffer_u32;
var SAMPLE_COUNT = 4 * 1024;
var SAMPLE_MASK = SAMPLE_COUNT - 1;
var audio_samples_L = new Float32Array(SAMPLE_COUNT);
var audio_samples_R = new Float32Array(SAMPLE_COUNT);
function getParameter(t) {
var e = window.location.search,
i = new RegExp(t + "=([^&?]*)", "ig");
return e.match(i) ? e.match(i)[0].substr(t.length + 1) : null
}
var netmode = !!getParameter("roomId");
var gameId = getParameter("id");
var worker = new Worker('./js/nes-worker.js');
worker.postMessage({
f: "netmode",
data: netmode
});
var KEY_MAP = {
ST: 13,
SE: 9,
A: 65,
B: 83,
Y: 50,
X: 49,
AB: [65, 83],
UP: 38,
DOWN: 40,
LEFT: 37,
RIGHT: 39,
L_D: [37, 40],
L_U: [37, 38],
R_D: [39, 40],
R_U: [39, 38]
};
var player = 1;
window.vm = {
oldDire: null,
keyEvent: function (t, e, i) {
var r = KEY_MAP[t];
Array.isArray(r) ? (vm.simulateKeyPress(r[0], e), vm.simulateKeyPress(r[1], e)) : vm.simulateKeyPress(r, e)
},
initCtrl: function () {
var s;
vm.initGameDireCtrl(function (t, e) {
var i = -1 == t ? s : ["DOWN", "L_D", "LEFT", "L_U", "UP", "R_U", "RIGHT", "R_D"][t],
r = -1 == t;
s && (s != i || r) && vm.keyEvent(s, "keyup", e), s = i, !r && vm.keyEvent(i, "keydown", e)
}), vm.initGameKeyCtrl(), $(".ctrl-wrap").on("click contextmenu touchstart touchmove touchend touchcancel tap", function (t) {
return t.stopPropagation(), t.preventDefault(), !1
})
},
initGameDireCtrl: function (u) {
var d = this,
t = $(".dire-wrap"),
p = $(".dc-centre"),
e = $(".dire-ctrl"),
l = $(".dc-dire"),
i = e.offset(),
n = i.top,
a = i.left,
f = p.width() / 2,
m = e.width() / 2,
r = function () {
p.css({
transform: "translate3d(83px,83px,0)"
}), p.css("opacity", "1"), l.css("opacity", "0")
},
y = function (t, e) {
var i = t[e];
if (!i) return {
x: 160,
y: 500
};
var r = i.pageX - a,
s = i.pageY - n;
return 600 < s ? y(t, e + 1) : {
x: r,
y: s
}
};
r(), t.on("touchstart touchmove", function (t) {
var e, i, r = y(t.touches, 0),
s = r.x,
n = r.y,
a = Math.atan2(n - m, s - m) / (Math.PI / 180);
if (l.css("transform", "rotate(" + a + "deg)"), d.onCtrlDire(a, u), (e = m - s, i = m - n, Math.sqrt(e * e + i * i)) <= 86) {
var o = s - f,
h = n - f;
p.css("transform", "translate3d(" + o + "px," + h + "px,0)")
} else {
var c = a * Math.PI / 180;
o = m + 86 * Math.cos(c) - f, h = m + 86 * Math.sin(c) - f;
p.css("transform", "translate3d(" + o + "px," + h + "px,0)")
}
"touchstart" === t.type && (p.css("opacity", "0.8"), l.css("opacity", "0.6"))
}).on("touchend", function () {
r(), u(-1, 0), d.oldDire = -1
})
},
initGameKeyCtrl: function () {
var s = this;
$(".key-btn").bind("touchstart touchend", function (t) {
var e = $(t.target),
i = e.attr("data-key"),
r = "touchstart" === t.type;
s.keyEvent(i, r ? "keydown" : "keyup", 0), e[r ? "addClass" : "removeClass"]("btn-on")
})
},
onCtrlDire: function (t, e) {
this.onCtrlDire;
var i;//= Math.round((t + 180) / 45) % 8;
var abst = Math.abs(t);
if ((abst >= 35 && abst <= 55) || (abst >= 125 && abst <= 145)) {
i = Math.round((t + 180) / 45) % 8;
} else {
i = Math.round((t + 180) / 90) % 4 * 2;
}
this.oldDire != i && (e(i, t), this.oldDire = i)
},
simulateKeyPress: function (t, e) {
if (!netmode) {
worker.postMessage({
f: "keypad",
data: {keyCode: t, action: e}
});
} else {
var data = {
m: NetEnum.JUMP,
v: {
keyCode: t,
keyaction: e,
player: player
}
}
NetWorkManage.sendFrameEvent(data);
}
}
};
function startGame() {
var path = "https://h5games-al.kingsome.cn/emulator-static/roms/" + gameId + ".nes"
nes_load_url("screen", path)
vm.initCtrl()
if (netmode) {
var roomId = getParameter("roomId")
NetWorkManage.initengine();
NetWorkManage.cbOnLogin = function (res) {
if (res.status === 0) {
console.log(res)
NetWorkManage.cbOnLogin = null;
if (roomId === "0") {
NetWorkManage.engine.createRoom('testroom', 2, "");
} else {
player = 2;
NetWorkManage.engine.joinRoom(roomId, "");
}
}
}
NetWorkManage.cbOnJoinRoom = function (res) {
NetWorkManage.gameStart();
};
var updateframe = function () {
if (NetWorkManage.frames.length > 0) {
var fr = NetWorkManage.frames.shift();
if (fr.isnet) {
NetWorkHandle.processFrame(fr);
}
worker.postMessage({f: "updateframe"});
if (fr.frameIndex < NetWorkManage.frameIndex) {
updateframe();
}
}
}
setInterval(function () {
updateframe();
}, 1000 / 60)
}
}
function checkSession_id(res) {
try {
if (JSON.parse(res.target.response).errcode === 0) {
startGame();
}
} catch (e) {
}
}
window.onload = function () {
var noCheck = getParameter('nt');
if (noCheck) {
startGame()
} else {
var account_id = getParameter("account_id")
var session_id = getParameter("session_id")
var url;
if (getParameter("version") === "product") {
url = "https://login.kingsome.cn/webapp/index.php?c=Login&a=sessionAuth"
} else {
url = "https://login-test.kingsome.cn/webapp/index.php?c=Login&a=sessionAuth"
}
url += "&account_id=";
url += account_id;
url += "&session_id=";
url += session_id;
var ajax = new XMLHttpRequest();
ajax.onload = checkSession_id;
ajax.open("GET", url, true);
ajax.send(null);
}
}
var script_processor = null
var audio_ctx = null
function initAudioEvent() {
script_processor && (script_processor.disconnect(audio_ctx.destination), script_processor.onaudioprocess = null, script_processor = null)
audio_ctx && audio_ctx.close().catch(handleError)
window.AudioContext = window.webkitAudioContext || window.AudioContext
audio_ctx = new window.AudioContext();
script_processor = audio_ctx.createScriptProcessor(4096, 0, 2);
script_processor.onaudioprocess = audio_callback;
script_processor.connect(audio_ctx.destination);
$(".key-btn").unbind("touchstart", initAudioEvent)
}
function audio_callback(e) {
var dst = e.outputBuffer;
var len = dst.length;
var dst_l = dst.getChannelData(0);
var dst_r = dst.getChannelData(1);
for (var i = 0; i < len; i++) {
var src_idx = (audio_read_cursor + i) & SAMPLE_MASK;
dst_l[i] = audio_samples_L[src_idx];
dst_r[i] = audio_samples_R[src_idx];
}
audio_read_cursor = (audio_read_cursor + len) & SAMPLE_MASK;
}
function nes_init(canvas_id) {
var canvas = document.getElementById(canvas_id);
canvas_ctx = canvas.getContext("2d");
image = canvas_ctx.getImageData(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
canvas_ctx.fillStyle = "black";
canvas_ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
var buffer = new ArrayBuffer(image.data.length);
worker.postMessage({
f: "setBuffer",
data: image.data.length
});
framebuffer_u8 = new Uint8ClampedArray(buffer);
framebuffer_u32 = new Uint32Array(buffer);
$(".key-btn").bind("touchstart", initAudioEvent)
}
function nes_boot(rom_data) {
worker.postMessage({
f: "nesloadROM",
data: rom_data
});
}
function nes_load_url(canvas_id, path) {
nes_init(canvas_id);
var req = new XMLHttpRequest();
req.open("GET", path);
req.overrideMimeType("text/plain; charset=x-user-defined");
req.onerror = () => console.log(`Error loading ${path}: ${req.statusText}`);
req.onload = function () {
if (this.status === 200) {
nes_boot(this.responseText);
} else if (this.status === 0) {
// Aborted, so ignore error
} else {
req.onerror();
}
};
req.send();
}
worker.onmessage = function (event) {
if (event.data.f === "frame") {
// framebuffer_u8 = event.data.data
image.data.set(event.data.data.framebuffer_u8);
canvas_ctx.putImageData(image, 0, 0);
audio_samples_L = event.data.data.audio_samples_L
audio_samples_R = event.data.data.audio_samples_R
audio_read_cursor = event.data.data.audio_read_cursor
} else if (event.data.f === 'saveData') {
let data = zip(event.data.data);
console.log(data);
localStorage.setItem(gameId, data);
}
}
document.addEventListener('keydown', (event) => {
console.log(event.keyCode);
worker.postMessage({
f: "keypad",
data: {keyCode: event.keyCode, action: 'keydown'}
});
});
document.addEventListener('keyup', (event) => {
if (event.keyCode === 83) {
//save
worker.postMessage({
f: "save",
});
}else if (event.keyCode === 82) {
//save
worker.postMessage({
f: "reload",
});
} else if (event.keyCode === 76) {
//load
var saveData = localStorage.getItem(gameId);
if( saveData == null ) {
console.log("nothing to load");
alert("请先保存.");
return;
}
let unzipData = unzip(saveData);
var decodedData = JSON.parse(unzipData);
worker.postMessage({
f: "load",
data: decodedData
});
}
worker.postMessage({
f: "keypad",
data: {keyCode: event.keyCode, action: 'keyup'}
});
});
function unzip(binaryString) {
return unescape(pako.inflate(binaryString, { to: 'string' }));
}
// 压缩
function zip(str) {
//escape(str) --->压缩前编码,防止中午乱码
var binaryString = pako.gzip(escape(str), {to: 'string'});
return binaryString;
}

158
fc2/js/nes-worker.js Normal file
View File

@ -0,0 +1,158 @@
if('function' === typeof importScripts) {
importScripts('./jsnes.min.js');
}
var SCREEN_WIDTH = 256;
var SCREEN_HEIGHT = 240;
var FRAMEBUFFER_SIZE = SCREEN_WIDTH * SCREEN_HEIGHT;
var framebuffer_u8, framebuffer_u32;
var AUDIO_BUFFERING = 512;
var SAMPLE_COUNT = 4 * 1024;
var SAMPLE_MASK = SAMPLE_COUNT - 1;
var audio_samples_L = new Float32Array(SAMPLE_COUNT);
var audio_samples_R = new Float32Array(SAMPLE_COUNT);
var audio_write_cursor = 0
, audio_read_cursor = 0;
var netmode = false;
var nes = new jsnes.NES({
onFrame: function(framebuffer_24) {
for (var i = 0; i < FRAMEBUFFER_SIZE; i++)
framebuffer_u32[i] = 0xFF000000 | framebuffer_24[i];
},
onAudioSample: function(l, r) {
audio_samples_L[audio_write_cursor] = l;
audio_samples_R[audio_write_cursor] = r;
audio_write_cursor = (audio_write_cursor + 1) & SAMPLE_MASK;
},
});
function keyboard(callback, event, p) {
var player = p || 1;
switch (event.keyCode) {
case 38:
// UP
callback(player, jsnes.Controller.BUTTON_UP);
break;
case 40:
// Down
callback(player, jsnes.Controller.BUTTON_DOWN);
break;
case 37:
// Left
callback(player, jsnes.Controller.BUTTON_LEFT);
break;
case 39:
// Right
callback(player, jsnes.Controller.BUTTON_RIGHT);
break;
case 65:
// 'a' - qwerty, dvorak
case 81:
// 'q' - azerty
callback(player, jsnes.Controller.BUTTON_A);
break;
case 83:
// 's' - qwerty, azerty
case 79:
// 'o' - dvorak
callback(player, jsnes.Controller.BUTTON_B);
break;
case 9:
// Tab
callback(player, jsnes.Controller.BUTTON_SELECT);
break;
case 13:
// Return
callback(player, jsnes.Controller.BUTTON_START);
break;
default:
break;
}
}
onmessage = function(event) {
switch (event.data.f) {
case 'nesloadROM':
nes.loadROM(event.data.data);
if (netmode === false) {
setInterval(function() {
nes.frame();
postMessage({
f: "frame",
data: {
framebuffer_u8: framebuffer_u8,
audio_samples_L: audio_samples_L,
audio_samples_R: audio_samples_R,
audio_read_cursor: audio_read_cursor,
}
});
}, 1000 / 60)
}
break;
case 'updateframe':
nes.frame();
postMessage({
f: "frame",
data: {
framebuffer_u8: framebuffer_u8,
audio_samples_L: audio_samples_L,
audio_samples_R: audio_samples_R,
audio_read_cursor: audio_read_cursor,
}
});
break;
case 'netmode':
netmode = event.data.data;
break;
case 'setBuffer':
var buffer = new ArrayBuffer(event.data.data);
framebuffer_u8 = new Uint8ClampedArray(buffer);
framebuffer_u32 = new Uint32Array(buffer);
break;
case 'keypad':
if (event.data.data.action === "keydown") {
keyboard(nes.buttonDown, event.data.data)
} else {
keyboard(nes.buttonUp, event.data.data)
}
break;
case 'netkeypad':
if (event.data.data.keyaction === "keydown") {
keyboard(nes.buttonDown, event.data.data, event.data.data.player)
} else {
keyboard(nes.buttonUp, event.data.data, event.data.data.player)
}
break;
case 'netframe':
nes.frame();
postMessage({
f: "frame",
data: {
framebuffer_u8: framebuffer_u8,
audio_samples_L: audio_samples_L,
audio_samples_R: audio_samples_R,
audio_read_cursor: audio_read_cursor,
}
});
break;
case 'save':
var currData = nes.toJSON();
var saveData = JSON.stringify(currData);
postMessage({
f: "saveData",
data: saveData
});
break;
case 'load':
var decodedData = event.data.data;
console.log(decodedData);
nes.fromJSON(decodedData);
break;
case 'reload':
nes.reloadROM();
break;
}
//console.log('11Received message ' + event.data);
// doSomething();
}

37
fc2/js/options.js Normal file
View File

@ -0,0 +1,37 @@
$(function () {
let keyType = Cookies.get('key_type') || 'N';
console.log(`keyType: ${keyType}`);
let setKeyType = function (keyType) {
$("[name=key_type]").val([keyType]);
if (keyType === 'N') {
$('#ctrl-wrap').addClass('real');
$('#menu_btn').addClass('real');
} else {
$('#ctrl-wrap').removeClass('real');
$('#menu_btn').removeClass('real');
}
Cookies.set('key_type', keyType);
}
setKeyType(keyType);
$('#menu_btn').click(function () {
console.log('menu btn click');
showMenu();
});
let showMenu = function() {
$('#menu_back').show();
$('#menu_container').removeClass('hidden');
}
let hideMenu = function() {
$('#menu_back').hide();
$('#menu_container').addClass('hidden');
}
$('#cancel_btn').click(function () {
hideMenu();
})
$('#save_btn').click(function () {
keyType = $('input[name="key_type"]:checked').val();
setKeyType(keyType);
hideMenu();
})
})

6818
fc2/js/pako.js Normal file

File diff suppressed because it is too large Load Diff

27
fc2/source/controller.js Normal file
View File

@ -0,0 +1,27 @@
var Controller = function() {
this.state = new Array(8);
for (var i = 0; i < this.state.length; i++) {
this.state[i] = 0x40;
}
};
Controller.BUTTON_A = 0;
Controller.BUTTON_B = 1;
Controller.BUTTON_SELECT = 2;
Controller.BUTTON_START = 3;
Controller.BUTTON_UP = 4;
Controller.BUTTON_DOWN = 5;
Controller.BUTTON_LEFT = 6;
Controller.BUTTON_RIGHT = 7;
Controller.prototype = {
buttonDown: function(key) {
this.state[key] = 0x41;
},
buttonUp: function(key) {
this.state[key] = 0x40;
}
};
module.exports = Controller;

2024
fc2/source/cpu.js Normal file

File diff suppressed because it is too large Load Diff

4
fc2/source/index.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
Controller: require("./controller"),
NES: require("./nes")
};

1518
fc2/source/mappers.js Normal file

File diff suppressed because it is too large Load Diff

210
fc2/source/nes.js Normal file
View File

@ -0,0 +1,210 @@
var CPU = require("./cpu");
var Controller = require("./controller");
var PPU = require("./ppu");
var PAPU = require("./papu");
var ROM = require("./rom");
var NES = function(opts) {
this.opts = {
onFrame: function() {},
onAudioSample: null,
onStatusUpdate: function() {},
onBatteryRamWrite: function() {},
// FIXME: not actually used except for in PAPU
preferredFrameRate: 60,
emulateSound: true,
sampleRate: 44100 // Sound sample rate in hz
};
if (typeof opts !== "undefined") {
var key;
for (key in this.opts) {
if (typeof opts[key] !== "undefined") {
this.opts[key] = opts[key];
}
}
}
this.frameTime = 1000 / this.opts.preferredFrameRate;
this.ui = {
writeFrame: this.opts.onFrame,
updateStatus: this.opts.onStatusUpdate
};
this.cpu = new CPU(this);
this.ppu = new PPU(this);
this.papu = new PAPU(this);
this.mmap = null; // set in loadROM()
this.controllers = {
1: new Controller(),
2: new Controller()
};
this.ui.updateStatus("Ready to load a ROM.");
this.frame = this.frame.bind(this);
this.buttonDown = this.buttonDown.bind(this);
this.buttonUp = this.buttonUp.bind(this);
this.zapperMove = this.zapperMove.bind(this);
this.zapperFireDown = this.zapperFireDown.bind(this);
this.zapperFireUp = this.zapperFireUp.bind(this);
};
NES.prototype = {
fpsFrameCount: 0,
romData: null,
// Resets the system
reset: function() {
if (this.mmap !== null) {
this.mmap.reset();
}
this.cpu.reset();
this.ppu.reset();
this.papu.reset();
this.lastFpsTime = null;
this.fpsFrameCount = 0;
},
frame: function() {
this.ppu.startFrame();
var cycles = 0;
var emulateSound = this.opts.emulateSound;
var cpu = this.cpu;
var ppu = this.ppu;
var papu = this.papu;
FRAMELOOP: for (;;) {
if (cpu.cyclesToHalt === 0) {
// Execute a CPU instruction
cycles = cpu.emulate();
if (emulateSound) {
papu.clockFrameCounter(cycles);
}
cycles *= 3;
} else {
if (cpu.cyclesToHalt > 8) {
cycles = 24;
if (emulateSound) {
papu.clockFrameCounter(8);
}
cpu.cyclesToHalt -= 8;
} else {
cycles = cpu.cyclesToHalt * 3;
if (emulateSound) {
papu.clockFrameCounter(cpu.cyclesToHalt);
}
cpu.cyclesToHalt = 0;
}
}
for (; cycles > 0; cycles--) {
if (
ppu.curX === ppu.spr0HitX &&
ppu.f_spVisibility === 1 &&
ppu.scanline - 21 === ppu.spr0HitY
) {
// Set sprite 0 hit flag:
ppu.setStatusFlag(ppu.STATUS_SPRITE0HIT, true);
}
if (ppu.requestEndFrame) {
ppu.nmiCounter--;
if (ppu.nmiCounter === 0) {
ppu.requestEndFrame = false;
ppu.startVBlank();
break FRAMELOOP;
}
}
ppu.curX++;
if (ppu.curX === 341) {
ppu.curX = 0;
ppu.endScanline();
}
}
}
this.fpsFrameCount++;
},
buttonDown: function(controller, button) {
this.controllers[controller].buttonDown(button);
},
buttonUp: function(controller, button) {
this.controllers[controller].buttonUp(button);
},
zapperMove: function(x, y) {
if (!this.mmap) return;
this.mmap.zapperX = x;
this.mmap.zapperY = y;
},
zapperFireDown: function() {
if (!this.mmap) return;
this.mmap.zapperFired = true;
},
zapperFireUp: function() {
if (!this.mmap) return;
this.mmap.zapperFired = false;
},
getFPS: function() {
var now = +new Date();
var fps = null;
if (this.lastFpsTime) {
fps = this.fpsFrameCount / ((now - this.lastFpsTime) / 1000);
}
this.fpsFrameCount = 0;
this.lastFpsTime = now;
return fps;
},
reloadROM: function() {
if (this.romData !== null) {
this.loadROM(this.romData);
}
},
// Loads a ROM file into the CPU and PPU.
// The ROM file is validated first.
loadROM: function(data) {
// Load ROM file:
this.rom = new ROM(this);
this.rom.load(data);
this.reset();
this.mmap = this.rom.createMapper();
this.mmap.loadROM();
this.ppu.setMirroring(this.rom.getMirroringType());
this.romData = data;
},
setFramerate: function(rate) {
this.opts.preferredFrameRate = rate;
this.frameTime = 1000 / rate;
this.papu.setSampleRate(this.opts.sampleRate, false);
},
toJSON: function() {
return {
romData: this.romData,
cpu: this.cpu.toJSON(),
mmap: this.mmap.toJSON(),
ppu: this.ppu.toJSON()
};
},
fromJSON: function(s) {
this.loadROM(s.romData);
this.cpu.fromJSON(s.cpu);
this.mmap.fromJSON(s.mmap);
this.ppu.fromJSON(s.ppu);
}
};
module.exports = NES;

1371
fc2/source/papu.js Normal file

File diff suppressed because it is too large Load Diff

1753
fc2/source/ppu.js Normal file

File diff suppressed because it is too large Load Diff

204
fc2/source/rom.js Normal file
View File

@ -0,0 +1,204 @@
var Mappers = require("./mappers");
var Tile = require("./tile");
var ROM = function(nes) {
this.nes = nes;
this.mapperName = new Array(92);
for (var i = 0; i < 92; i++) {
this.mapperName[i] = "Unknown Mapper";
}
this.mapperName[0] = "Direct Access";
this.mapperName[1] = "Nintendo MMC1";
this.mapperName[2] = "UNROM";
this.mapperName[3] = "CNROM";
this.mapperName[4] = "Nintendo MMC3";
this.mapperName[5] = "Nintendo MMC5";
this.mapperName[6] = "FFE F4xxx";
this.mapperName[7] = "AOROM";
this.mapperName[8] = "FFE F3xxx";
this.mapperName[9] = "Nintendo MMC2";
this.mapperName[10] = "Nintendo MMC4";
this.mapperName[11] = "Color Dreams Chip";
this.mapperName[12] = "FFE F6xxx";
this.mapperName[15] = "100-in-1 switch";
this.mapperName[16] = "Bandai chip";
this.mapperName[17] = "FFE F8xxx";
this.mapperName[18] = "Jaleco SS8806 chip";
this.mapperName[19] = "Namcot 106 chip";
this.mapperName[20] = "Famicom Disk System";
this.mapperName[21] = "Konami VRC4a";
this.mapperName[22] = "Konami VRC2a";
this.mapperName[23] = "Konami VRC2a";
this.mapperName[24] = "Konami VRC6";
this.mapperName[25] = "Konami VRC4b";
this.mapperName[32] = "Irem G-101 chip";
this.mapperName[33] = "Taito TC0190/TC0350";
this.mapperName[34] = "32kB ROM switch";
this.mapperName[64] = "Tengen RAMBO-1 chip";
this.mapperName[65] = "Irem H-3001 chip";
this.mapperName[66] = "GNROM switch";
this.mapperName[67] = "SunSoft3 chip";
this.mapperName[68] = "SunSoft4 chip";
this.mapperName[69] = "SunSoft5 FME-7 chip";
this.mapperName[71] = "Camerica chip";
this.mapperName[78] = "Irem 74HC161/32-based";
this.mapperName[91] = "Pirate HK-SF3 chip";
};
ROM.prototype = {
// Mirroring types:
VERTICAL_MIRRORING: 0,
HORIZONTAL_MIRRORING: 1,
FOURSCREEN_MIRRORING: 2,
SINGLESCREEN_MIRRORING: 3,
SINGLESCREEN_MIRRORING2: 4,
SINGLESCREEN_MIRRORING3: 5,
SINGLESCREEN_MIRRORING4: 6,
CHRROM_MIRRORING: 7,
header: null,
rom: null,
vrom: null,
vromTile: null,
romCount: null,
vromCount: null,
mirroring: null,
batteryRam: null,
trainer: null,
fourScreen: null,
mapperType: null,
valid: false,
load: function(data) {
var i, j, v;
if (data.indexOf("NES\x1a") === -1) {
throw new Error("Not a valid NES ROM.");
}
this.header = new Array(16);
for (i = 0; i < 16; i++) {
this.header[i] = data.charCodeAt(i) & 0xff;
}
this.romCount = this.header[4];
this.vromCount = this.header[5] * 2; // Get the number of 4kB banks, not 8kB
this.mirroring = (this.header[6] & 1) !== 0 ? 1 : 0;
this.batteryRam = (this.header[6] & 2) !== 0;
this.trainer = (this.header[6] & 4) !== 0;
this.fourScreen = (this.header[6] & 8) !== 0;
this.mapperType = (this.header[6] >> 4) | (this.header[7] & 0xf0);
/* TODO
if (this.batteryRam)
this.loadBatteryRam();*/
// Check whether byte 8-15 are zero's:
var foundError = false;
for (i = 8; i < 16; i++) {
if (this.header[i] !== 0) {
foundError = true;
break;
}
}
if (foundError) {
this.mapperType &= 0xf; // Ignore byte 7
}
// Load PRG-ROM banks:
this.rom = new Array(this.romCount);
var offset = 16;
for (i = 0; i < this.romCount; i++) {
this.rom[i] = new Array(16384);
for (j = 0; j < 16384; j++) {
if (offset + j >= data.length) {
break;
}
this.rom[i][j] = data.charCodeAt(offset + j) & 0xff;
}
offset += 16384;
}
// Load CHR-ROM banks:
this.vrom = new Array(this.vromCount);
for (i = 0; i < this.vromCount; i++) {
this.vrom[i] = new Array(4096);
for (j = 0; j < 4096; j++) {
if (offset + j >= data.length) {
break;
}
this.vrom[i][j] = data.charCodeAt(offset + j) & 0xff;
}
offset += 4096;
}
// Create VROM tiles:
this.vromTile = new Array(this.vromCount);
for (i = 0; i < this.vromCount; i++) {
this.vromTile[i] = new Array(256);
for (j = 0; j < 256; j++) {
this.vromTile[i][j] = new Tile();
}
}
// Convert CHR-ROM banks to tiles:
var tileIndex;
var leftOver;
for (v = 0; v < this.vromCount; v++) {
for (i = 0; i < 4096; i++) {
tileIndex = i >> 4;
leftOver = i % 16;
if (leftOver < 8) {
this.vromTile[v][tileIndex].setScanline(
leftOver,
this.vrom[v][i],
this.vrom[v][i + 8]
);
} else {
this.vromTile[v][tileIndex].setScanline(
leftOver - 8,
this.vrom[v][i - 8],
this.vrom[v][i]
);
}
}
}
this.valid = true;
},
getMirroringType: function() {
if (this.fourScreen) {
return this.FOURSCREEN_MIRRORING;
}
if (this.mirroring === 0) {
return this.HORIZONTAL_MIRRORING;
}
return this.VERTICAL_MIRRORING;
},
getMapperName: function() {
if (this.mapperType >= 0 && this.mapperType < this.mapperName.length) {
return this.mapperName[this.mapperType];
}
return "Unknown Mapper, " + this.mapperType;
},
mapperSupported: function() {
return typeof Mappers[this.mapperType] !== "undefined";
},
createMapper: function() {
if (this.mapperSupported()) {
return new Mappers[this.mapperType](this.nes);
} else {
throw new Error(
"This ROM uses a mapper not supported by JSNES: " +
this.getMapperName() +
"(" +
this.mapperType +
")"
);
}
}
};
module.exports = ROM;

198
fc2/source/tile.js Normal file
View File

@ -0,0 +1,198 @@
var Tile = function() {
// Tile data:
this.pix = new Array(64);
this.fbIndex = null;
this.tIndex = null;
this.x = null;
this.y = null;
this.w = null;
this.h = null;
this.incX = null;
this.incY = null;
this.palIndex = null;
this.tpri = null;
this.c = null;
this.initialized = false;
this.opaque = new Array(8);
};
Tile.prototype = {
setBuffer: function(scanline) {
for (this.y = 0; this.y < 8; this.y++) {
this.setScanline(this.y, scanline[this.y], scanline[this.y + 8]);
}
},
setScanline: function(sline, b1, b2) {
this.initialized = true;
this.tIndex = sline << 3;
for (this.x = 0; this.x < 8; this.x++) {
this.pix[this.tIndex + this.x] =
((b1 >> (7 - this.x)) & 1) + (((b2 >> (7 - this.x)) & 1) << 1);
if (this.pix[this.tIndex + this.x] === 0) {
this.opaque[sline] = false;
}
}
},
render: function(
buffer,
srcx1,
srcy1,
srcx2,
srcy2,
dx,
dy,
palAdd,
palette,
flipHorizontal,
flipVertical,
pri,
priTable
) {
if (dx < -7 || dx >= 256 || dy < -7 || dy >= 240) {
return;
}
this.w = srcx2 - srcx1;
this.h = srcy2 - srcy1;
if (dx < 0) {
srcx1 -= dx;
}
if (dx + srcx2 >= 256) {
srcx2 = 256 - dx;
}
if (dy < 0) {
srcy1 -= dy;
}
if (dy + srcy2 >= 240) {
srcy2 = 240 - dy;
}
if (!flipHorizontal && !flipVertical) {
this.fbIndex = (dy << 8) + dx;
this.tIndex = 0;
for (this.y = 0; this.y < 8; this.y++) {
for (this.x = 0; this.x < 8; this.x++) {
if (
this.x >= srcx1 &&
this.x < srcx2 &&
this.y >= srcy1 &&
this.y < srcy2
) {
this.palIndex = this.pix[this.tIndex];
this.tpri = priTable[this.fbIndex];
if (this.palIndex !== 0 && pri <= (this.tpri & 0xff)) {
//console.log("Rendering upright tile to buffer");
buffer[this.fbIndex] = palette[this.palIndex + palAdd];
this.tpri = (this.tpri & 0xf00) | pri;
priTable[this.fbIndex] = this.tpri;
}
}
this.fbIndex++;
this.tIndex++;
}
this.fbIndex -= 8;
this.fbIndex += 256;
}
} else if (flipHorizontal && !flipVertical) {
this.fbIndex = (dy << 8) + dx;
this.tIndex = 7;
for (this.y = 0; this.y < 8; this.y++) {
for (this.x = 0; this.x < 8; this.x++) {
if (
this.x >= srcx1 &&
this.x < srcx2 &&
this.y >= srcy1 &&
this.y < srcy2
) {
this.palIndex = this.pix[this.tIndex];
this.tpri = priTable[this.fbIndex];
if (this.palIndex !== 0 && pri <= (this.tpri & 0xff)) {
buffer[this.fbIndex] = palette[this.palIndex + palAdd];
this.tpri = (this.tpri & 0xf00) | pri;
priTable[this.fbIndex] = this.tpri;
}
}
this.fbIndex++;
this.tIndex--;
}
this.fbIndex -= 8;
this.fbIndex += 256;
this.tIndex += 16;
}
} else if (flipVertical && !flipHorizontal) {
this.fbIndex = (dy << 8) + dx;
this.tIndex = 56;
for (this.y = 0; this.y < 8; this.y++) {
for (this.x = 0; this.x < 8; this.x++) {
if (
this.x >= srcx1 &&
this.x < srcx2 &&
this.y >= srcy1 &&
this.y < srcy2
) {
this.palIndex = this.pix[this.tIndex];
this.tpri = priTable[this.fbIndex];
if (this.palIndex !== 0 && pri <= (this.tpri & 0xff)) {
buffer[this.fbIndex] = palette[this.palIndex + palAdd];
this.tpri = (this.tpri & 0xf00) | pri;
priTable[this.fbIndex] = this.tpri;
}
}
this.fbIndex++;
this.tIndex++;
}
this.fbIndex -= 8;
this.fbIndex += 256;
this.tIndex -= 16;
}
} else {
this.fbIndex = (dy << 8) + dx;
this.tIndex = 63;
for (this.y = 0; this.y < 8; this.y++) {
for (this.x = 0; this.x < 8; this.x++) {
if (
this.x >= srcx1 &&
this.x < srcx2 &&
this.y >= srcy1 &&
this.y < srcy2
) {
this.palIndex = this.pix[this.tIndex];
this.tpri = priTable[this.fbIndex];
if (this.palIndex !== 0 && pri <= (this.tpri & 0xff)) {
buffer[this.fbIndex] = palette[this.palIndex + palAdd];
this.tpri = (this.tpri & 0xf00) | pri;
priTable[this.fbIndex] = this.tpri;
}
}
this.fbIndex++;
this.tIndex--;
}
this.fbIndex -= 8;
this.fbIndex += 256;
}
}
},
isTransparent: function(x, y) {
return this.pix[(y << 3) + x] === 0;
},
toJSON: function() {
return {
opaque: this.opaque,
pix: this.pix
};
},
fromJSON: function(s) {
this.opaque = s.opaque;
this.pix = s.pix;
}
};
module.exports = Tile;

25
fc2/source/utils.js Normal file
View File

@ -0,0 +1,25 @@
module.exports = {
copyArrayElements: function(src, srcPos, dest, destPos, length) {
for (var i = 0; i < length; ++i) {
dest[destPos + i] = src[srcPos + i];
}
},
copyArray: function(src) {
return src.slice(0);
},
fromJSON: function(obj, state) {
for (var i = 0; i < obj.JSON_PROPERTIES.length; i++) {
obj[obj.JSON_PROPERTIES[i]] = state[obj.JSON_PROPERTIES[i]];
}
},
toJSON: function(obj) {
var state = {};
for (var i = 0; i < obj.JSON_PROPERTIES.length; i++) {
state[obj.JSON_PROPERTIES[i]] = obj[obj.JSON_PROPERTIES[i]];
}
return state;
}
};

View File

@ -1,130 +1,7 @@
var gulp = require('gulp'),
concat = require('gulp-concat'),
// uglify = require('gulp-uglify'),
uglify = require('gulp-uglify-es').default,
rename = require('gulp-rename'),
jshint = require('gulp-jshint'),
stripDebug = require("gulp-strip-debug"),//移除console语句
cleanCSS = require('gulp-clean-css'),
gutil = require('gulp-util');
const javascriptObfuscator = require('gulp-javascript-obfuscator');
const obfuscatorOptions = {
compact:true,
sourceMap: false,
debugProtection: true,
disableConsoleOutput: true,
domainLock: ['.kingsome.cn', '.zhl.com']
};
//检查js的语法错误
gulp.task('jslint', function () {
return gulp.src('fc/js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(notify({message: 'finished jslint'}));
});
//发布所有html
gulp.task('disthtml', function(){
return gulp.src(['**/*.html', '!node_modules/**/*', '!dist/**/*'])
.pipe(gulp.dest('dist'));
})
//处理fc的css
gulp.task('distfccss', function() {
return gulp.src(['fc/css/**/*.css'])
.pipe(cleanCSS())
.pipe(gulp.dest('dist/fc/css'));
})
//处理fc的图片资源
gulp.task('distfcstatic', function() {
return gulp.src(['fc/resources/**/*'])
.pipe(gulp.dest('dist/fc/resources'));
})
gulp.task('distfclib', function() {
return gulp.src(['fc/lib/**/*'])
.pipe(gulp.dest('dist/fc/lib'));
})
gulp.task('distfcjs', function() {
return gulp.src(['fc/js/**/*.js'])
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/fc/js'));
});
gulp.task('distfc', ['distfcjs', 'distfccss', 'distfcstatic', 'distfclib'])
let gulpRequireTasks = require('gulp-require-tasks');
let gulp = require('gulp')
gulp.task('distgbajs', function() {
return gulp.src(['gba/dist/*.js'])
// .pipe(concat('main.js'))
// .pipe(rename({suffix: '.min'}))
//https://github.com/mishoo/UglifyJS2
// .pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/gba/dist'));
});
gulp.task('distgbacss', function() {
return gulp.src(['gba/dist/**/*.css'])
.pipe(gulp.dest('dist/gba/dist'));
})
gulp.task('distgbastatic', function() {
return gulp.src(['gba/resources/**/*'])
.pipe(gulp.dest('dist/gba/resources'));
})
gulp.task('distgbajsext', function() {
return gulp.src(['gba/js/**/*'])
.pipe(gulp.dest('dist/gba/js'));
})
gulp.task('distgba', ['distgbajs', 'distgbacss', 'distgbastatic', 'distgbajsext'])
gulp.task('distgba2js', function() {
return gulp.src(['gba2/dist/*.js'])
// .pipe(concat('main.js'))
// .pipe(rename({suffix: '.min'}))
//https://github.com/mishoo/UglifyJS2
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/gba2/dist'));
});
gulp.task('distgba2css', function() {
return gulp.src(['gba2/dist/**/*.css'])
.pipe(cleanCSS())
.pipe(gulp.dest('dist/gba2/dist'));
})
gulp.task('distgba2static', function() {
return gulp.src(['gba2/resources/**/*'])
.pipe(gulp.dest('dist/gba2/resources'));
})
gulp.task('distgba2bios', function() {
return gulp.src(['gba2/Binaries/**/*'])
.pipe(gulp.dest('dist/gba2/Binaries'));
})
gulp.task('distgba2jscore', function() {
return gulp.src(['gba2/IodineGBA/**/*'])
.pipe(gulp.dest('dist/gba2/IodineGBA'));
})
gulp.task('distgba2jsuser', function() {
return gulp.src(['gba2/user_scripts/**/*'])
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/gba2/user_scripts'));
})
gulp.task('distgba2', ['distgba2js', 'distgba2css', 'distgba2static', 'distgba2bios', 'distgba2jscore', 'distgba2jsuser'])
gulp.task('assets', function() {
return gulp.src(['assets/**/*'])
.pipe(gulp.dest('dist/assets'));
})
// movie
gulp.task('distmoviejs', function() {
return gulp.src(['movie/js/*.js'])
.pipe(stripDebug())
.pipe(gulp.dest('dist/movie/js'));
});
gulp.task('distmoviecss', function() {
return gulp.src(['movie/css/**/*.css'])
.pipe(gulp.dest('dist/movie/css'));
})
gulp.task('distmoviestatic', function() {
return gulp.src(['movie/img/**/*'])
.pipe(gulp.dest('dist/movie/img'));
})
gulp.task('distmovie', ['distmoviejs', 'distmoviecss', 'distmoviestatic'])
gulp.task('default', ['disthtml', 'distfc', 'distgba', 'distgba2', 'distmovie', 'assets']);
// gulp.task('default', ['disthtml', 'distfc', 'assets']);
gulpRequireTasks({
path: __dirname + '/tasks',
gulp: gulp
});

40
package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "emulator",
"version": "1.0.0",
"description": "",
"main": "",
"devDependencies": {
"babel-preset-env": "^1.7.0",
"eslint": "^5.16.0",
"eslint-loader": "^2.1.2",
"gulp": "^3.9.1",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4.0.0",
"gulp-concat": "^2.6.1",
"gulp-javascript-obfuscator": "^1.1.5",
"gulp-jshint": "^2.1.0",
"gulp-minify-css": "^1.2.4",
"gulp-module-wrapper": "^0.3.8",
"gulp-notify": "^3.2.0",
"gulp-rename": "^1.4.0",
"gulp-require-tasks": "^1.2.1",
"gulp-sourcemaps": "^2.6.5",
"gulp-strip-debug": "^3.0.0",
"gulp-uglify": "^3.0.2",
"gulp-uglify-es": "^1.0.4",
"gulp-util": "^3.0.8",
"jshint": "^2.10.1",
"path": "^0.12.7",
"gulp-browserify": "^0.5.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build_fc_lib": "webpack --config tasks/fc2.webpack.js"
},
"repository": {
"type": "git",
"url": "git@git.kingsome.cn:weapp/emulator.git"
},
"author": "",
"license": "ISC"
}

134
tasks/dist.js Normal file
View File

@ -0,0 +1,134 @@
var gulp = require('gulp'),
concat = require('gulp-concat'),
// uglify = require('gulp-uglify'),
uglify = require('gulp-uglify-es').default,
rename = require('gulp-rename'),
jshint = require('gulp-jshint'),
stripDebug = require("gulp-strip-debug"),//移除console语句
cleanCSS = require('gulp-clean-css'),
gutil = require('gulp-util');
const javascriptObfuscator = require('gulp-javascript-obfuscator');
const obfuscatorOptions = {
compact:true,
sourceMap: false,
debugProtection: true,
disableConsoleOutput: true,
domainLock: ['.kingsome.cn', '.zhl.com']
};
//检查js的语法错误
gulp.task('jslint', function () {
return gulp.src('fc/js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(notify({message: 'finished jslint'}));
});
//发布所有html
gulp.task('disthtml', function(){
return gulp.src(['**/*.html', '!node_modules/**/*', '!dist/**/*'])
.pipe(gulp.dest('dist'));
})
//处理fc的css
gulp.task('distfccss', function() {
return gulp.src(['fc/css/**/*.css'])
.pipe(cleanCSS())
.pipe(gulp.dest('dist/fc/css'));
})
//处理fc的图片资源
gulp.task('distfcstatic', function() {
return gulp.src(['fc/resources/**/*'])
.pipe(gulp.dest('dist/fc/resources'));
})
gulp.task('distfclib', function() {
return gulp.src(['fc/lib/**/*'])
.pipe(gulp.dest('dist/fc/lib'));
})
gulp.task('distfcjs', function() {
return gulp.src(['fc/js/**/*.js'])
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/fc/js'));
});
gulp.task('distfc', ['distfcjs', 'distfccss', 'distfcstatic', 'distfclib'])
gulp.task('distgbajs', function() {
return gulp.src(['gba/dist/*.js'])
// .pipe(concat('main.js'))
// .pipe(rename({suffix: '.min'}))
//https://github.com/mishoo/UglifyJS2
// .pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/gba/dist'));
});
gulp.task('distgbacss', function() {
return gulp.src(['gba/dist/**/*.css'])
.pipe(gulp.dest('dist/gba/dist'));
})
gulp.task('distgbastatic', function() {
return gulp.src(['gba/resources/**/*'])
.pipe(gulp.dest('dist/gba/resources'));
})
gulp.task('distgbajsext', function() {
return gulp.src(['gba/js/**/*'])
.pipe(gulp.dest('dist/gba/js'));
})
gulp.task('distgba', ['distgbajs', 'distgbacss', 'distgbastatic', 'distgbajsext'])
gulp.task('distgba2js', function() {
return gulp.src(['gba2/dist/*.js'])
// .pipe(concat('main.js'))
// .pipe(rename({suffix: '.min'}))
//https://github.com/mishoo/UglifyJS2
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/gba2/dist'));
});
gulp.task('distgba2css', function() {
return gulp.src(['gba2/dist/**/*.css'])
.pipe(cleanCSS())
.pipe(gulp.dest('dist/gba2/dist'));
})
gulp.task('distgba2static', function() {
return gulp.src(['gba2/resources/**/*'])
.pipe(gulp.dest('dist/gba2/resources'));
})
gulp.task('distgba2bios', function() {
return gulp.src(['gba2/Binaries/**/*'])
.pipe(gulp.dest('dist/gba2/Binaries'));
})
gulp.task('distgba2jscore', function() {
return gulp.src(['gba2/IodineGBA/**/*'])
.pipe(gulp.dest('dist/gba2/IodineGBA'));
})
gulp.task('distgba2jsuser', function() {
return gulp.src(['gba2/user_scripts/**/*'])
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/gba2/user_scripts'));
})
gulp.task('distgba2', ['distgba2js', 'distgba2css', 'distgba2static', 'distgba2bios', 'distgba2jscore', 'distgba2jsuser'])
gulp.task('assets', function() {
return gulp.src(['assets/**/*'])
.pipe(gulp.dest('dist/assets'));
})
// movie
gulp.task('distmoviejs', function() {
return gulp.src(['movie/js/*.js'])
.pipe(stripDebug())
.pipe(gulp.dest('dist/movie/js'));
});
gulp.task('distmoviecss', function() {
return gulp.src(['movie/css/**/*.css'])
.pipe(gulp.dest('dist/movie/css'));
})
gulp.task('distmoviestatic', function() {
return gulp.src(['movie/img/**/*'])
.pipe(gulp.dest('dist/movie/img'));
})
gulp.task('distmovie', ['distmoviejs', 'distmoviecss', 'distmoviestatic'])
gulp.task('default', ['disthtml', 'distfc', 'distgba', 'distgba2', 'distmovie', 'assets']);
// gulp.task('default', ['disthtml', 'distfc', 'assets']);
module.exports = {
dep: ['default'],
};

54
tasks/fc2.js Normal file
View File

@ -0,0 +1,54 @@
const gulp = require('gulp'),
concat = require('gulp-concat'),
// uglify = require('gulp-uglify'),
uglify = require('gulp-uglify-es').default,
rename = require('gulp-rename'),
jshint = require('gulp-jshint'),
stripDebug = require("gulp-strip-debug"),//移除console语句
cleanCSS = require('gulp-clean-css'),
gutil = require('gulp-util'),
browserify = require('gulp-browserify'),
javascriptObfuscator = require('gulp-javascript-obfuscator');
const obfuscatorOptions = {
compact:true,
sourceMap: false,
debugProtection: false,
disableConsoleOutput: false
};
//处理fc的css
gulp.task('distfccss', function() {
return gulp.src(['fc2/css/**/*.css'])
.pipe(cleanCSS())
.pipe(gulp.dest('dist/fc2/css'));
})
//处理fc的图片资源
gulp.task('distfcstatic', function() {
return gulp.src(['fc2/images/**/*'])
.pipe(gulp.dest('dist/fc2/images'));
})
gulp.task('distfcjs', function() {
return gulp.src(['fc2/js/**/*.js'])
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(stripDebug())
.pipe(gulp.dest('dist/fc2/js'));
});
gulp.task('distlib', function () {
return gulp.src('fc2/source/index.js')
.pipe(browserify({
insertGlobals : false,
debug: false,
standalone: 'jsnes'
}))
.pipe(javascriptObfuscator(obfuscatorOptions))
.pipe(rename('jsnes.min.js'))
.pipe(gulp.dest('dist/fc2/js/'));
});
gulp.task('distfc', ['distfcjs', 'distfccss', 'distfcstatic', 'distlib'])
module.exports = {
dep: ['distfc'],
};