इंजीनियरिंग को उल्टा करें और गो पर फ्लैश गेम्स के लिए एक बॉट लिखें

छवि इस लेख में, मैं आपको बताऊंगा कि फ्लैश एप्लिकेशन को डिकम्पोज कैसे किया जाए और फिर गेम सर्वर पर एल्गोरिथ्म साइन करने का अनुरोध निकालें। और इस जानकारी के आधार पर गो पर गेम बॉट लिखने के लिए कैसे।
यह सब इस तथ्य से शुरू हुआ कि मैं अपने एंड्रॉइड स्मार्टफोन के साथ खेलने की रणनीति की तलाश कर रहा था। "सिंहासन की भीड़" नामक एक अच्छा खेल मिला। फिर यह पता चला कि एक ब्राउज़र क्लाइंट भी है, जो कुछ कार्यों को अधिक सुविधाजनक बनाता है। लेकिन फिर भी, गेमप्ले में स्पष्ट रूप से स्वचालन की आवश्यकता होती है। मैंने उत्कृष्ट उपकरण JPEXS फ्री फ़्लैश डेकोम्पेलर का उपयोग किया, जिस पर बाद में चर्चा की जाएगी।

गिटहब पर परियोजना का स्रोत कोड।

तो, कार्य एक मूल ग्राहक के काम का अनुकरण करना है।
Firebug'om संचार फ़्लैश अनुप्रयोगों को देखने
POST https://epicwar-facebook.progrestar.net/rpc/ Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding gzip, deflate Accept-Language uk Connection keep-alive Cookie __utma=252078920.1702705582.1400051769.1400051769.1400051769.1; __utmz=252078920.1400051769.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) Host epicwar-facebook.progrestar.net User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:29.0) Gecko/20100101 Firefox/29.0 Content-Length 1913 Content-Type application/json; charset=UTF-8 X-Auth-Application-Id 1424411677784893 X-Auth-Network-Ident facebook X-Auth-Session-Id 0n5nkrp20i8sf9 X-Auth-Session-Init 1 X-Auth-Signature 57d0320e91c26cd8e56152d3aad1a809 X-Auth-Token 6514a97ae525f196b8060337380e0cbb X-Auth-User-Id 675063875 X-Env-Library-Version 0 X-Request-Id 1 X-Requested-With XMLHttpRequest X-Server-Time 1400219523 {"calls":[{"name":"registration","args":{"user":{"locale":"en","id":"675063875","birthday":"1970-1-1","referrer":{"type":"bookmark"},"lastName":"","city":null,"country":null,"firstName":"","sex":"female"},"friendIds":[]},"ident":"registration"},{"name":"boostGetAll","args":{},"ident":"boostGetAll"},{"name":"getTime","args":{},"ident":"getTime"},{"name":"getSelfInfo","args":{},"ident":"getSelfInfo"},{"name":"getDynamicParams","args":{},"ident":"getDynamicParams"},{"name":"getArmyQueue","args":{},"ident":"getArmyQueue"},{"name":"getBuildings","args":{},"ident":"getBuildings"},{"name":"heroesGetList","args":{},"ident":"heroesGetList"},{"name":"getResearchQueue","args":{},"ident":"getResearchQueue"},{"name":"getMissions","args":{},"ident":"getMissions"},{"name":"getQuests","args":{},"ident":"getQuests"},{"name":"getProtections","args":{},"ident":"getProtections"},{"name":"getInvitedBy","args":{},"ident":"getInvitedBy"},{"name":"getInvitedUsers","args":{},"ident":"getInvitedUsers"},{"name":"getBonusCrystals","args":{},"ident":"getBonusCrystals"},{"name":"getSettings","args":{},"ident":"getSettings"},{"name":"promoGetHalfBilling","args":{},"ident":"promoGetHalfBilling"},{"name":"giftGetAvailable","args":{},"ident":"giftGetAvailable"},{"name":"giftGetReceivers","args":{},"ident":"giftGetReceivers"},{"name":"cloverGetAll","args":{},"ident":"cloverGetAll"},{"name":"paymentsCount","args":{},"ident":"paymentsCount"},{"name":"cemeteryGet","args":{},"ident":"cemeteryGet"},{"name":"getNotices","args":{},"ident":"getNotices"},{"name":"allianceGetMessages","args":{},"ident":"allianceGetMessages"},{"name":"getGlobalNews","args":{},"ident":"getGlobalNews"},{"name":"battleGetActive","args":{},"ident":"battleGetActive"},{"name":"spellList","args":{},"ident":"spellList"},{"name":"spellProductionQueue","args":{},"ident":"spellProductionQueue"},{"name":"state","args":{},"ident":"state"}],"session":null} 


यह X-Auth- हस्ताक्षर के साथ समस्या है। मुझे नहीं पता था कि यह कहां मिलेगा। जाहिर है, यह किसी न किसी तरह की हैश है। लेकिन क्या और क्या अज्ञात है। "FFDec" ने मुझे इससे मदद की। ओपन सोर्स प्रोग्राम, जो जावा द्वारा लिखा गया है, लिनक्स के तहत चलता है। इस नौकरी के लिए बिल्कुल सही।
Html कोड दिखाता है कि कौन सी फाइल लोड हो रही है।

 <object id="flash-app" width="100%" height="100%" data="https://epicwar-a.akamaihd.net/facebook/static/assets/Start.swf?v=13" type="application/x-shockwave-flash"> 

लेकिन वास्तव में, यह वह नहीं है जो आपको चाहिए। हम फ्लैशवार्स देखते हैं। वहाँ "प्रीलोडर = https% 3A% 2F% 2Fepicwar-a.akamaihd.net% 2Ffacebook% 2Fv042% 2FFbLoader.swf% 3Fv% 3D2"। लेकिन यह फिर से मामला नहीं है। और आवश्यक कोड, मुझे ठीक से याद नहीं है कि मैंने इसे कैसे समझा, वास्तव में यहाँ https://epicwar-a.akamaihd.net/facebook/v042/EpicWar.swf

हम विघटित हो रहे हैं।
प्रोग्राम विंडो


वास्तव में, वहाँ निर्यात है।
यहां डिकम्पोज्ड कोड है
 protected function createHeaders(param1:RpcEntryBase) : Object { var _loc5_:String = null; var _loc2_:String = SocialAdapter.instance.flashVars["session_key"]; var _loc3_:Object = { "Content-Type":"application/json; charset=UTF-8", "X-Request-Id":++this.unionRequestID, "X-Auth-Network-Ident":Env.NETWORK, "X-Auth-Application-Id":SocialAdapter.instance.app_id, "X-Auth-User-Id":SocialAdapter.instance.getPlayer().id, "X-Auth-Session-Id":Env.sessionKey }; if(_loc2_ != null) { _loc3_["X-Auth-Session-Key"] = _loc2_; } var _loc4_:Object = param1.headers; if(_loc4_ != null) { for(_loc5_ in _loc4_) { _loc3_[_loc5_] = _loc4_[_loc5_]; } } return _loc3_; } protected function createAuthSignature(param1:Object, param2:RpcEntryBase) : ByteArray { var _loc5_:ByteArray = null; var _loc3_:Object = param2.request.getFormattedData(); var _loc4_:ByteArray = new ByteArray(); _loc4_.writeUTFBytes(param1["X-Request-Id"]); _loc4_.writeUTFBytes(":"); _loc4_.writeUTFBytes(SocialAdapter.instance.authentication_key); _loc4_.writeUTFBytes(":"); _loc4_.writeUTFBytes(param1["X-Auth-Session-Id"]); _loc4_.writeUTFBytes(":"); if(_loc3_ is ByteArray) { _loc5_ = _loc3_ as ByteArray; _loc5_.position = 0; _loc4_.writeBytes(_loc5_,0,_loc5_.length); } else if(_loc3_ is String) { _loc4_.writeUTFBytes(_loc3_ as String); } _loc4_.writeUTFBytes(":"); _loc4_.writeUTFBytes(this.createFingerprint(param1)); return _loc4_; } private function createFingerprint(param1:Object) : String { var _loc4_:String = null; var _loc5_:* = 0; var _loc6_:* = 0; var _loc7_:String = null; var _loc2_:Array = []; var _loc3_:* = ""; for(_loc4_ in param1) { if(_loc4_.indexOf("X-Env") != -1) { _loc7_ = _loc4_.substr(6); _loc2_.push( { "key":_loc7_.toUpperCase(), "value":param1[_loc4_] }); } } _loc2_.sortOn("key"); _loc5_ = _loc2_.length; _loc6_ = 0; while(_loc6_ < _loc5_) { _loc3_ = _loc3_ + (_loc2_[_loc6_].key + "=" + _loc2_[_loc6_].value); _loc6_++; } return _loc3_; } protected function addHeaders(param1:URLRequest, param2:RpcEntryBase) : void { var _loc4_:String = null; var _loc3_:Object = this.createHeaders(param2); var _loc5_:ByteArray = this.createAuthSignature(_loc3_,param2); _loc3_["X-Auth-Signature"] = MD5.hashBytes(_loc5_); for(_loc4_ in _loc3_) { param1.requestHeaders.push(new URLRequestHeader(_loc4_,_loc3_[_loc4_].toString())); } } 


सब कुछ सरल है। सामान्य md5। नीचे गो पर यह कोड है।
नेटवर्क
 package network import ( "net/http" "strings" "bytes" "crypto/md5" "io" "encoding/hex" "strconv" "io/ioutil" "log" ) const SERVER_URL = "https://epicwar-facebook.progrestar.net/rpc/" const APP_ID = "1424411677784893" const AUTH_KEY = "6514a97ae525f196b8060337380e0cbb" const NETWORK = "facebook" var _unionRequestID int var _uid string var _sid string func createFingerprint(headers map[string]string) string { var fingerprint bytes.Buffer preparedHeaders := []Pair{} for header, _ := range headers{ if(strings.Index(header, "X-Env") != -1){ preparedHeaders = append(preparedHeaders, Pair{ key : strings.ToUpper(header[6:len(header)]), value : headers[header]}) } } sortByKey(preparedHeaders) count := len(preparedHeaders); i := 0; for i < count { fingerprint.WriteString(preparedHeaders[i].key) fingerprint.WriteString("=") fingerprint.WriteString(preparedHeaders[i].value) i++; } res := fingerprint.String() return res } func createAuthSignature (headers map[string]string, postData string) string { h := md5.New() io.WriteString(h, headers["X-Request-Id"]) io.WriteString(h, ":") io.WriteString(h, AUTH_KEY); io.WriteString(h, ":"); io.WriteString(h, headers["X-Auth-Session-Id"]); io.WriteString(h, ":"); io.WriteString(h, postData); io.WriteString(h, ":"); io.WriteString(h, createFingerprint(headers)); return hex.EncodeToString(h.Sum(nil)) } func createHeaders() (map[string]string) { _unionRequestID = _unionRequestID + 1 headers := map[string]string{ "X-Request-Id":strconv.Itoa(_unionRequestID), "X-Auth-Network-Ident":NETWORK, "X-Auth-Application-Id":APP_ID, "X-Auth-User-Id":_uid, "X-Auth-Session-Id":_sid, "X-Env-Library-Version": "0"} return headers } func addHeaders(req *http.Request, postData string) { headers := createHeaders(); headers["X-Auth-Signature"] = createAuthSignature(headers, postData); for index, header := range headers { req.Header.Add(index, header) } } func Post(postData []byte) []byte { client := &http.Client{} req, err := http.NewRequest("POST", SERVER_URL, bytes.NewReader(postData)) addHeaders(req, string(postData)) resp, err := client.Do(req) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if(err != nil){ log.Fatal(err) } return body } func Init(Uid string, Sid string) { _unionRequestID = 0 _uid = Uid _sid = Sid } 


जाहिरा तौर पर, मैं शानदार शीर्षकों को नहीं भेजता हूं। एक्शन स्क्रिप्ट कोड में, RpcClientBase वर्ग को "com.progrestar.game.server.rpc" से RpcClient वर्ग द्वारा विरासत में मिला है और अधिक हेडर प्रदान करता है। उदाहरण के लिए, “X-Env-Library-Version” मैंने वहाँ से लिया था। उसके बिना काम नहीं चलता।

क्वेरी जनरेशन फ़ंक्शंस
 package bot import ( "log" "encoding/json" ) func getFormattedData(calls Calls) []byte { data, err := json.Marshal(Request{Calls:calls, Session: nil}) if(err != nil){ log.Fatal(err) } return data } func getStartBoard() []byte { return getFormattedData(Calls{ Call{Name:"getSelfInfo",Args:struct{}{},Ident:"getSelfInfo"}, Call{Name:"getBuildings",Args:struct{}{},Ident:"getBuildings"}}) } func collectResource(building uint64) []byte { return getFormattedData(Calls{ Call{ Name:"collectResource", Args:struct{BuildingId uint64 `json:"buildingId"`}{BuildingId:building}, Ident:"group_0_body"}, Call{Name:"state", Args: struct{}{}, Ident:"group_1_body"}}) } func upgradeBuilding(building uint64) []byte { return getFormattedData(Calls{ Call{ Name:"upgradeBuilding", Args:struct{BuildingId uint64 `json:"buildingId"`}{BuildingId:building}, Ident:"group_0_body"}, Call{Name:"state", Args: struct{}{}, Ident:"group_1_body"}}) } 


डेटा संरचनाएं
 package bot type Unit struct { Id uint64 `json:"id"` Amount uint64 `json:"amount"` } type Building struct { Id uint64 `json:"id"` TypeId uint `json:"typeId"` Flip bool `json:"flip"` Level uint `json:"level"` X uint `json:"x"` Y uint `json:"y"` Completed bool `json:"completed"` Volume uint `json:"volume"` StateTimestamp uint64 `json:"stateTimestamp"` Hitpoints uint64 `json:"hitpoints"` CompleteTime uint64 `json:"completeTime"` } type Player struct { Units []Unit Buildings []Building Stars uint //interlan game currency Level uint Builders int //Builder house lvl GoldCapacity uint32 FoodCapacity uint32 Food uint32 Gold uint32 CastleLvl uint } type Result struct { Ident string `json:"ident"` Result map[string]interface{} `json:"result"` } type Error struct { Name string `json:"name"` Description string `json:"description"` Call `json:"call"` } type Response struct{ Date float64 `json:"date"` Results []Result `json:"results"` Error Error `json:"error"` } type BuildingDependency struct { CastleLvl uint Cost uint32 } type BuildingDependencies []BuildingDependency type Buildings struct { Wall BuildingDependencies } type Call struct { Ident string `json:"ident"` Args interface {} `json:"args"` Name string `json:"name"` } type Calls []Call type Request struct { Calls Calls `json:"calls"` Session interface{} `json:"session"` } 


रिवर्स इंजीनियरिंग का हिस्सा खत्म हो गया है। अब बॉट के तर्क का हिस्सा। मैंने मूल ग्राहक में खेलने का अवसर छोड़ दिया। ब्राउज़र में ऐसा करने के लिए, http: // localhost: 8080 / original पर जाएं
मॉड्यूल कोड
 package main import ( "net/http" "log" "./utils" ) type Pair struct { Key string Value string } func original(Uid string) { flashvars := []Pair{ Pair{"fb_source", "bookmark"}, Pair{"ref", "bookmarks"}, Pair{"count", "0"}, Pair{"fb_bmpos", "2_0"}, Pair{"code", "AQA9KrPoSxjyTjNoG9B1mUHoZ8ooUxusmPWV6Aa17SfgHIkSVubBwLxCKC5EO7fkfIiC9LvnrDOY35pzlPwyasKVe6q1dcOZzvyQeTmrlf-rhjjMH0FZGh0PWwMp0k3IqZTg1tKunkFFGMALgo4Vf8vSzGFG2r8DiJq5-N7K-5MIg7j3VnR0A0-EzaM5kATvrM5FmI1XWmxHbHFmHpS52rKuTvSuH27Ipwt4p2V2DGayvPDjnvvfs6d5-hdaCtoxoOvBJDfecDakToecSzr3kAU6zF4QiMCIC1MtihaH_3C7a9BeLdVqMhr4w4q33WqEso0"}, Pair{"sys_id", "4"}, Pair{"network", "facebook"}, Pair{"uid", Uid}, Pair{"app_id", "1424411677784893"}, Pair{"interface_lang", "uk"}, Pair{"access_token", "CAAUPfrARez0BAKDb5H1uds5kLg3794HyPAbTYRZAA1H2i43NPl8sSjpxl77gIqDapYZB4QxWrZAK1H6VQUVAFbWuTWr4VYbXagirvciMba7FhyYKSUboICrvSJKYgBndShSZA0n4ZA5JRZBqigVbMRdCsHrjl8AQEmcWfbJqkHflqmv8XEBarKEVJRfLp56ksLZCO7TBzkfVQZDZD"}, Pair{"auth_key", "6514a97ae525f196b8060337380e0cbb"}, Pair{"requestLoadingInfoTimeout", "3000"}, Pair{"ref", "bookmark"}, Pair{"rpc_url", "https%3A%2F%2Fepicwar-facebook.progrestar.net%2Frpc%2F"}, Pair{"preloader_asset", "preloader%2Fpreloader_dwarf.swf"}, Pair{"browser", "chrome"}, Pair{"country_code", "UA"}, Pair{"geoip_city", "Kiev"}, Pair{"index_version", "1398240421"}, Pair{"static_url", "https%3A%2F%2Fepicwar-a.akamaihd.net%2F"}, Pair{"preloader", "https%3A%2F%2Fepicwar-a.akamaihd.net%2Ffacebook%2Fv042%2FFbLoader.swf%3Fv%3D2"}, Pair{"rpc_url", "https%3A%2F%2Fepicwar-facebook.progrestar.net%2Frpc%2F"}, Pair{"stat_url", "https://stat.progrestar.net/collector/client/"}, Pair{"error_url", "https://error.progrestar.net/client/"}, } t := utils.Template("original") http.HandleFunc("/original", func (w http.ResponseWriter, r *http.Request) { err := t.Execute(w, struct{Flashvars []Pair}{Flashvars: flashvars}) if err != nil { log.Fatal("There was an error:", err) } }) } -rhjjMH0FZGh0PWwMp0k3IqZTg1tKunkFFGMALgo4Vf8vSzGFG2r8DiJq5-N7K-5MIg7j3VnR0A0-EzaM5kATvrM5FmI1XWmxHbHFmHpS52rKuTvSuH27Ipwt4p2V2DGayvPDjnvvfs6d5-hdaCtoxoOvBJDfecDakToecSzr3kAU6zF4QiMCIC1MtihaH_3C7a9BeLdVqMhr4w4q33WqEso0"}, package main import ( "net/http" "log" "./utils" ) type Pair struct { Key string Value string } func original(Uid string) { flashvars := []Pair{ Pair{"fb_source", "bookmark"}, Pair{"ref", "bookmarks"}, Pair{"count", "0"}, Pair{"fb_bmpos", "2_0"}, Pair{"code", "AQA9KrPoSxjyTjNoG9B1mUHoZ8ooUxusmPWV6Aa17SfgHIkSVubBwLxCKC5EO7fkfIiC9LvnrDOY35pzlPwyasKVe6q1dcOZzvyQeTmrlf-rhjjMH0FZGh0PWwMp0k3IqZTg1tKunkFFGMALgo4Vf8vSzGFG2r8DiJq5-N7K-5MIg7j3VnR0A0-EzaM5kATvrM5FmI1XWmxHbHFmHpS52rKuTvSuH27Ipwt4p2V2DGayvPDjnvvfs6d5-hdaCtoxoOvBJDfecDakToecSzr3kAU6zF4QiMCIC1MtihaH_3C7a9BeLdVqMhr4w4q33WqEso0"}, Pair{"sys_id", "4"}, Pair{"network", "facebook"}, Pair{"uid", Uid}, Pair{"app_id", "1424411677784893"}, Pair{"interface_lang", "uk"}, Pair{"access_token", "CAAUPfrARez0BAKDb5H1uds5kLg3794HyPAbTYRZAA1H2i43NPl8sSjpxl77gIqDapYZB4QxWrZAK1H6VQUVAFbWuTWr4VYbXagirvciMba7FhyYKSUboICrvSJKYgBndShSZA0n4ZA5JRZBqigVbMRdCsHrjl8AQEmcWfbJqkHflqmv8XEBarKEVJRfLp56ksLZCO7TBzkfVQZDZD"}, Pair{"auth_key", "6514a97ae525f196b8060337380e0cbb"}, Pair{"requestLoadingInfoTimeout", "3000"}, Pair{"ref", "bookmark"}, Pair{"rpc_url", "https%3A%2F%2Fepicwar-facebook.progrestar.net%2Frpc%2F"}, Pair{"preloader_asset", "preloader%2Fpreloader_dwarf.swf"}, Pair{"browser", "chrome"}, Pair{"country_code", "UA"}, Pair{"geoip_city", "Kiev"}, Pair{"index_version", "1398240421"}, Pair{"static_url", "https%3A%2F%2Fepicwar-a.akamaihd.net%2F"}, Pair{"preloader", "https%3A%2F%2Fepicwar-a.akamaihd.net%2Ffacebook%2Fv042%2FFbLoader.swf%3Fv%3D2"}, Pair{"rpc_url", "https%3A%2F%2Fepicwar-facebook.progrestar.net%2Frpc%2F"}, Pair{"stat_url", "https://stat.progrestar.net/collector/client/"}, Pair{"error_url", "https://error.progrestar.net/client/"}, } t := utils.Template("original") http.HandleFunc("/original", func (w http.ResponseWriter, r *http.Request) { err := t.Execute(w, struct{Flashvars []Pair}{Flashvars: flashvars}) if err != nil { log.Fatal("There was an error:", err) } }) } "}, package main import ( "net/http" "log" "./utils" ) type Pair struct { Key string Value string } func original(Uid string) { flashvars := []Pair{ Pair{"fb_source", "bookmark"}, Pair{"ref", "bookmarks"}, Pair{"count", "0"}, Pair{"fb_bmpos", "2_0"}, Pair{"code", "AQA9KrPoSxjyTjNoG9B1mUHoZ8ooUxusmPWV6Aa17SfgHIkSVubBwLxCKC5EO7fkfIiC9LvnrDOY35pzlPwyasKVe6q1dcOZzvyQeTmrlf-rhjjMH0FZGh0PWwMp0k3IqZTg1tKunkFFGMALgo4Vf8vSzGFG2r8DiJq5-N7K-5MIg7j3VnR0A0-EzaM5kATvrM5FmI1XWmxHbHFmHpS52rKuTvSuH27Ipwt4p2V2DGayvPDjnvvfs6d5-hdaCtoxoOvBJDfecDakToecSzr3kAU6zF4QiMCIC1MtihaH_3C7a9BeLdVqMhr4w4q33WqEso0"}, Pair{"sys_id", "4"}, Pair{"network", "facebook"}, Pair{"uid", Uid}, Pair{"app_id", "1424411677784893"}, Pair{"interface_lang", "uk"}, Pair{"access_token", "CAAUPfrARez0BAKDb5H1uds5kLg3794HyPAbTYRZAA1H2i43NPl8sSjpxl77gIqDapYZB4QxWrZAK1H6VQUVAFbWuTWr4VYbXagirvciMba7FhyYKSUboICrvSJKYgBndShSZA0n4ZA5JRZBqigVbMRdCsHrjl8AQEmcWfbJqkHflqmv8XEBarKEVJRfLp56ksLZCO7TBzkfVQZDZD"}, Pair{"auth_key", "6514a97ae525f196b8060337380e0cbb"}, Pair{"requestLoadingInfoTimeout", "3000"}, Pair{"ref", "bookmark"}, Pair{"rpc_url", "https%3A%2F%2Fepicwar-facebook.progrestar.net%2Frpc%2F"}, Pair{"preloader_asset", "preloader%2Fpreloader_dwarf.swf"}, Pair{"browser", "chrome"}, Pair{"country_code", "UA"}, Pair{"geoip_city", "Kiev"}, Pair{"index_version", "1398240421"}, Pair{"static_url", "https%3A%2F%2Fepicwar-a.akamaihd.net%2F"}, Pair{"preloader", "https%3A%2F%2Fepicwar-a.akamaihd.net%2Ffacebook%2Fv042%2FFbLoader.swf%3Fv%3D2"}, Pair{"rpc_url", "https%3A%2F%2Fepicwar-facebook.progrestar.net%2Frpc%2F"}, Pair{"stat_url", "https://stat.progrestar.net/collector/client/"}, Pair{"error_url", "https://error.progrestar.net/client/"}, } t := utils.Template("original") http.HandleFunc("/original", func (w http.ResponseWriter, r *http.Request) { err := t.Execute(w, struct{Flashvars []Pair}{Flashvars: flashvars}) if err != nil { log.Fatal("There was an error:", err) } }) } 


सभी फ्लैशवार्स को छोड़ दें, हालांकि मुझे लगता है कि कुछ की कोई आवश्यकता नहीं है।

संचार प्रोटोकॉल काफी सरल है। केवल POST अनुरोध और केवल एक URL। जीईटी / पीओटीएस अनुरोधों और मापदंडों की कोई बहुतायत नहीं है, जैसे कि ग्रेपॉलिस में।
बॉट, बदले में, अलग से एक गेम कार्ड प्राप्त करता है, इसे http: // localhost: 8080 / bot पर देखा जा सकता है। यहां केवल सुंदरियों और आइसोमेट्रिक्स के बिना एक नक्शा है। लेकिन दूसरी ओर, यह स्पष्ट रूप से दिखाई देता है कि ऐसी इमारत कहाँ है, जो शहर के बीच में खाली जगहों की उपस्थिति की संभावना को कम करती है, जहां दुश्मन लैंडिंग कर सकता है। मैंने अक्सर खुद ऐसा किया है। और मूल ग्राहक में, एक असुविधाजनक सममितीय प्रक्षेपण, जहां आप कोण को बदल नहीं सकते हैं, हमेशा सुविधाजनक नहीं होता है।

मैं संसाधनों को इकट्ठा करके शुरू करूंगा। यह बहुत सरल है। एक अलग गोरआउट बनाया जाता है, जो संसाधनों को इकट्ठा करता है, यदि संभव हो तो, और सो जाता है। उत्तर इमारतों और संसाधनों के साथ आता है, तथाकथित राज्य।

यहाँ संसाधन संग्राहक का स्रोत कोड है
 func processCollectRequest(player *Player, resp *Response){ for _, result := range resp.Results { if(result.Ident == "group_1_body"){ parseResources(player, result.Result["resource"].([]interface{})) parseBuildings(player, result.Result["building"].([]interface{})) } } } func collectFood(player *Player) *Response{ var resp *Response for _, building := range player.Buildings { if(building.TypeId == MILL_ID){ resp = decodeJson(network.Post(collectResource(building.Id))) } } return resp } func collectGold(player *Player) *Response{ var resp *Response for _, building := range player.Buildings { if(building.TypeId == MINE_ID){ resp = decodeJson(network.Post(collectResource(building.Id))) } } return resp } func resourcesCollector(playerChan chan Player) { var resp *Response var playerStruct Player var player *Player resp = nil playerStruct = <- playerChan player = &playerStruct if(player.FoodCapacity > player.Food){ log.Print("Collect Food") resp = collectFood(player) } if(player.GoldCapacity > player.Gold){ log.Print("Collect Gold") resp = collectGold(player) } if(resp != nil){ processCollectRequest(player, resp) resp = nil } playerChan <- playerStruct time.Sleep(time.Minute * 10) go resourcesCollector(playerChan) } 


एक अलग फ़ाइल स्थिरांक में।
 package bot const CASTLE_ID = 1 const MINE_ID = 2 const TREASURY_ID = 3 const MILL_ID = 4 const BARN_ID = 5 const BARRACKS_ID = 6 const STAFF_ID = 7 const BUILDER_HUT_ID = 8 const FORGE_ID = 9 const BALLISTA_ID = 10 const WALL_ID = 11 const ARCHER_TOWER_ID = 12 const CANNON_ID = 13 const THUNDER_TOWER_ID = 14 const ICE_TOWER_ID = 15 const FIRE_TOWER_ID = 16 const CLAN_HOUSE_ID = 17 const DARK_TOWER_ID = 18 const TAVERN_ID = 19 const ALCHEMIST_ID = 20 const GOLD_RESOURCE_ID = 1 const FOOD_RESOURCE_ID = 2 var CAPACITIES = [12]uint32 {0, 5000, 15000, 35000, 75000, 150000, 300000, 600000, 1000000, 2000000, 3000000, 4000000} var BUILDINGS = Buildings{ Wall: BuildingDependencies{ BuildingDependency{CastleLvl: 2, Cost: 250}, BuildingDependency{CastleLvl: 2, Cost: 500}, BuildingDependency{CastleLvl: 3, Cost: 1000}, BuildingDependency{CastleLvl: 4, Cost: 3000}, BuildingDependency{CastleLvl: 5, Cost: 10000}, BuildingDependency{CastleLvl: 6, Cost: 25000}, BuildingDependency{CastleLvl: 7, Cost: 60000}, BuildingDependency{CastleLvl: 8, Cost: 150000}, BuildingDependency{CastleLvl: 9, Cost: 400000}, BuildingDependency{CastleLvl: 10, Cost: 1000000}, BuildingDependency{CastleLvl: 11, Cost: 2000000}}} 


और पार्सर
 package bot import "log" func parseResources (player *Player, resources []interface{}){ for _, resource := range resources { var Id uint var Amount uint32 Id = uint(resource.(map[string]interface{})["id"].(float64)) Amount = uint32(resource.(map[string]interface{})["amount"].(float64)) if(Id == GOLD_RESOURCE_ID){ player.Gold = Amount log.Print("Gold - ", Amount) } if(Id == FOOD_RESOURCE_ID){ player.Food = Amount log.Print("Food - ", Amount) } } } func parseUnits (player *Player, units []interface{}){ player.Units = []Unit{} for _, unit := range units { player.Units = append( player.Units, Unit{ Id: uint64(unit.(map[string]interface{})["id"].(float64)), Amount: uint64(unit.(map[string]interface{})["amount"].(float64))}) } } func parseBuildings(player *Player, buildings []interface{}){ player.Buildings = []Building{} for _, building := range buildings { var typeId uint var level uint var completed bool typeId = uint(building.(map[string]interface{})["typeId"].(float64)) level = uint(building.(map[string]interface{})["level"].(float64)) completed = building.(map[string]interface{})["completed"].(bool) if(typeId == BARN_ID) { player.FoodCapacity += CAPACITIES[level] } if(typeId == TREASURY_ID) { player.GoldCapacity += CAPACITIES[level] } if(typeId == CASTLE_ID){ player.CastleLvl = level if(completed == false){ player.CastleLvl-- } } player.Buildings = append( player.Buildings, Building{ Id: uint64(building.(map[string]interface{})["id"].(float64)), TypeId: typeId, Flip: building.(map[string]interface{})["flip"].(bool), Level: level, X: uint(building.(map[string]interface{})["x"].(float64)), Y: uint(building.(map[string]interface{})["y"].(float64)), Completed: completed, Volume: uint(building.(map[string]interface{})["volume"].(float64)), StateTimestamp:uint64(building.(map[string]interface{})["stateTimestamp"].(float64)), Hitpoints: uint64(building.(map[string]interface{})["hitpoints"].(float64)), CompleteTime: uint64(building.(map[string]interface{})["completeTime"].(float64))}) } } 


मैंने केवल दीवारों के लिए इमारतों का ऑटो-सुधार किया, क्योंकि उनमें से कई हैं और प्रत्येक व्यक्तिगत ब्लॉक पर क्लिक करना बहुत असुविधाजनक है। जवाब में, एक ही राज्य आता है।
निर्माता
 func builder(playerChan chan Player){ var playerStruct Player var player *Player var resp *Response var isBuild bool = false playerStruct = <- playerChan player = &playerStruct for _, building := range player.Buildings { if( building.TypeId == WALL_ID && len(BUILDINGS.Wall) > int(building.Level) && player.CastleLvl >= BUILDINGS.Wall[building.Level].CastleLvl && player.Gold >= BUILDINGS.Wall[building.Level].Cost){ log.Print("Upgrade Wall. Level ", building.Level) resp = decodeJson(network.Post(upgradeBuilding(building.Id))) if(resp != nil){ processCollectRequest(player, resp) isBuild = true } break } } playerChan <- playerStruct if(isBuild){ time.Sleep(time.Second) }else{ time.Sleep(time.Hour) } go builder(playerChan) } 


मैं एक आरक्षण भी करूँगा कि यह संभव है कि केवल संदर्भ द्वारा एक संरचना को गोरोउटिन में स्थानांतरित किया जाए। लेकिन जब मैंने ऐसा किया, तो कचरा कलेक्टर ने थोड़ी देर बाद मेमोरी को साफ कर दिया और एक नलपॉइंट अपवाद को फेंक दिया। इसलिए, मैं चैनलों का उपयोग करता हूं।
मुख्य
 func decodeJson(encoded_json []byte) *Response { var resp *Response err := json.Unmarshal(encoded_json, &resp) if(err != nil){ log.Fatal("decodeJson", err) } if(resp.Error != Error{}){ resp = nil } return resp } func initGame(playerChan chan Player) { var playerStruct Player var player *Player playerStruct = Player{} player = &playerStruct resp := decodeJson(network.Post(getStartBoard())) for _, result := range resp.Results { if(result.Ident == "getSelfInfo"){ user := result.Result["user"].(map[string]interface{}) level, _ := strconv.Atoi(user["level"].(string)) player.Level = uint(level) player.Stars = uint(user["starmoney"].(float64)) parseUnits(player, user["unit"].([]interface{})) parseResources(player, user["resource"].([]interface{})) } player.GoldCapacity = 0 player.FoodCapacity = 0 if(result.Ident == "getBuildings"){ parseBuildings(player, result.Result["building"].([]interface{})) } } playerChan <- playerStruct } func Main(){ var player = make(chan Player, 1) initGame(player) go resourcesCollector(player) go builder(player) http.HandleFunc("/bot", func (w http.ResponseWriter, r *http.Request) { t, err := template.ParseFiles("static/bot.html") if err != nil { log.Fatal("There was an error:", err) } err = t.Execute(w, nil) if err != nil { log.Fatal("There was an error:", err) } }) http.HandleFunc("/bot/map", func (w http.ResponseWriter, r *http.Request) { var playerStruct Player = <- player player <- playerStruct json, err := json.Marshal(playerStruct) if(err != nil){ log.Fatal(err) } io.WriteString(w, string(json)) }) } 


मैं बॉट के ग्राहक भाग का भी प्रतिनिधित्व करूंगा। सबसे मुश्किल बात यह थी कि जिन जगहों पर इमारतें नहीं हैं, उन जगहों को बेहतर तरीके से प्रदर्शित किया जा सकता है, लेकिन वहां भी लैंडिंग नहीं की जा सकती है। बाकी बेहद साधारण है।
कौन बॉट क्लाइंट कोड की परवाह करता है
 <!doctype html> <html> <head> <title>Throne Rush Bot</title> <style> #main{ display:block; margin:0 auto; background-color:#00FF33; } body{ background-color:#66CC00; height: 100%; margin: 0; padding: 0; } html{ height: 100%; } </style> </head> <body> <canvas id="main"></canvas> <script> var STYLES = { 1: { name: "Castle", size: 5, fillColor: '#996600' }, 2: { name: "Mine", size: 2, fillColor: '#996600' }, 3: { name: "Treasury", size: 3, fillColor: '#996600' }, 4: { name: "Mill", size: 2, fillColor: '#996600' }, 5: { name: "Barn", size: 3, fillColor: '#996600' }, 6: { name: "Barracs", size: 3, fillColor: '#996600' }, 7: { name: "Staff", size: 2, fillColor: '#996600' }, 8: { name: "Bldrs", size: 2, fillColor: '#996600' }, 9: { name: "Forge", size: 2, fillColor: '#996600' }, 10: { name: "Ballista", size: 2, fillColor: '#996600' }, 11: { name: "", size: 1, fillColor: '#660000' }, 12: { name: "Archrs", size: 2, fillColor: '#996600' }, 13: { name: "Cannon", size: 2, fillColor: '#996600' }, 14: { name: "Thunder", size: 2, fillColor: '#996600' }, 15: { name: "Ice", size: 2, fillColor: '#996600' }, 16: { name: "Fire Tower", size: 2, fillColor: '#996600' }, 17: { name: "Clan house", size: 3, fillColor: '#996600' }, 18: { name: "Dark Tower", size: 2, fillColor: '#996600' }, 19: { name: "Tavern", size: 3, fillColor: '#996600' }, 20: { name: "Alchemist", size: 3, fillColor: '#996600' } }; var MAP_SIZE = 36; var NOT_DESANT_COLOR = "#FF0033"; var height = document.body.clientHeight; var canvas = document.getElementById('main'); var ctx = canvas.getContext('2d'); var step = height / 40; canvas.width = height; canvas.height = height; canvas.style.width = height + 'px'; canvas.style.height = height + 'px'; ctx.strokeStyle="#FF0033"; ctx.textAlign="center"; ctx.textBaseline="middle"; function pointFree(buildings, point){ for(var i in buildings){ var building = buildings[i]; if( point[0] >= building.x && point[0] < building.x + STYLES[building.typeId].size && point[1] >= building.y && point[1] < building.y + STYLES[building.typeId].size ){ return false; } } return true; } function drawMap(player){ var redPoints = []; player.Buildings .forEach(function(building){ for(var i = -1; i < STYLES[building.typeId].size + 1; i++){ var point = [building.x + i, building.y - 1].join(','); if(redPoints.indexOf(point) === -1){ redPoints.push(point); } } for(var i = -1; i < STYLES[building.typeId].size + 1; i++){ var point = [building.x + i, building.y + STYLES[building.typeId].size].join(','); if(redPoints.indexOf(point) === -1){ redPoints.push(point); } } for(var i = -1; i < STYLES[building.typeId].size + 1; i++){ var point = [building.x - 1, building.y + i].join(','); if(redPoints.indexOf(point) === -1){ redPoints.push(point); } } for(var i = -1; i < STYLES[building.typeId].size + 1; i++){ var point = [building.x + STYLES[building.typeId].size, building.y + i].join(','); if(redPoints.indexOf(point) === -1){ redPoints.push(point); } } ctx.fillStyle=STYLES[building.typeId].fillColor; ctx.fillRect( step * building.x, step * building.y, step * STYLES[building.typeId].size, step * STYLES[building.typeId].size); ctx.stroke(); ctx.strokeText( STYLES[building.typeId].name+'('+building.level+')', step * building.x + step * STYLES[building.typeId].size / 2, step * building.y + step * STYLES[building.typeId].size / 2); }); while(redPoints.length > 0){ var point = redPoints.pop().split(','); if(pointFree(player.Buildings, point)){ ctx.fillStyle=NOT_DESANT_COLOR; ctx.fillRect( step * point[0], step * point[1], step, step); ctx.stroke(); } } } var xmlhttp = new XMLHttpRequest(); xmlhttp.open('GET', '/bot/map', true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState === 4) { drawMap(JSON.parse(xmlhttp.responseText)) } }; xmlhttp.send(null); </script> </body> </html> 


तो वह दिखता है

Source: https://habr.com/ru/post/In223013/


All Articles