OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client SDK Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 /// @file | |
6 /// This example demonstrates loading, running and scripting a very simple NaCl | |
7 /// module. To load the NaCl module, the browser first looks for the | |
8 /// CreateModule() factory method (at the end of this file). It calls | |
9 /// CreateModule() once to load the module code from your .nexe. After the | |
10 /// .nexe code is loaded, CreateModule() is not called again. | |
11 /// | |
12 /// Once the .nexe code is loaded, the browser then calls the | |
13 /// HexGameModule::CreateInstance() | |
14 /// method on the object returned by CreateModule(). It calls CreateInstance() | |
15 /// each time it encounters an <embed> tag that references your NaCl module. | |
16 /// | |
17 | |
18 #include "hex_instance.h" | |
19 | |
20 namespace { | |
21 | |
22 /// Use @a delims to identify all the elements in @ the_string, and add | |
23 /// Invoke the function associated with @a method. The argument list passed | |
24 /// via JavaScript is marshaled into a vector of pp::Vars. None of the | |
25 /// functions in this example take arguments, so this vector is always empty. | |
26 /// these elements to the end of @a the_data. Return how many elements | |
27 /// were found. | |
28 /// @param the_string [in] A string containing the data to be parsed. | |
29 /// @param delims [in] A string containing the characters used as delimiters. | |
30 /// @param the_data [out] A vector of strings to which the elements are added. | |
31 /// @return The number of elements added to @ the_data. | |
32 /// | |
33 /// Example uses: | |
34 /// GetElementsFromString(arg0, std::string(" "), unitIds); | |
35 /// GetElementsFromString(green_substring, std::string("[]"), greenUnitWords); | |
36 int GetElementsFromString(std::string the_string, std::string delims, | |
37 std::vector<std::string>& the_data) { | |
38 size_t element_start = 0, element_end; | |
39 unsigned int elements_found = 0; | |
40 bool found_an_element = false; | |
41 do { | |
42 found_an_element = false; | |
43 // find first non-delimeter | |
44 element_start = the_string.find_first_not_of(delims, element_start); | |
45 if (element_start != std::string::npos) { | |
46 found_an_element = true; | |
47 element_end = the_string.find_first_of(delims, element_start+1); | |
48 std::string the_element = the_string.substr(element_start, | |
49 element_end - element_start); | |
50 the_data.push_back(the_element); | |
51 ++elements_found; | |
52 // Set element_start (where to look for non-delim) to element_end, which | |
53 // is where we found the last delim. Don't add 1 to element_end, or else | |
54 // we may start past the end of the string when last delim was last char | |
55 // of the string. | |
56 element_start = element_end; | |
57 } | |
58 } while (found_an_element); | |
59 return elements_found; | |
60 } | |
61 } // namespace | |
62 | |
63 namespace hexgame { | |
64 | |
65 // AppMain runs the original game loop (corresponding to main) | |
66 void* AppMain(void* param); | |
67 | |
68 | |
69 // Return an event from the thread-safe queue, waiting for a new event | |
70 // to occur if the queue is empty. Set |was_queue_cancelled| to indicate | |
71 // whether the queue was cancelled. If it was cancelled, then the | |
72 const UserMove HexGameInstance::GetEventFromQueue(bool *was_queue_cancelled) { | |
73 UserMove user_move(-1, -1); | |
74 | |
75 QueueGetResult result = event_queue_.GetItem(&user_move, kWait); | |
76 if (result == kQueueWasCancelled) { | |
77 *was_queue_cancelled = true; | |
78 } | |
79 *was_queue_cancelled = false; | |
80 return user_move; | |
81 } | |
82 | |
83 void HexGameInstance::WaitForUserMove(uint32_t* user_col, uint32_t* user_row) { | |
84 bool canceled; | |
85 UserMove move = GetEventFromQueue(&canceled); | |
86 *user_col = move.column_; | |
87 *user_row = move.row_; | |
88 } | |
89 | |
90 void HexGameInstance::GameOver() { | |
91 if (!computer_wins_ && !user_wins_) | |
92 return; | |
93 | |
94 std::string msg; | |
95 if (computer_wins_) { | |
96 msg = "COMPUTERWINS"; | |
97 } else { | |
98 msg = "USERWINS"; | |
99 } | |
100 printf("Calling PostMessage with [%s]\n", msg.c_str()); | |
101 PostMessage(pp::Var(msg)); | |
102 } | |
103 | |
104 // SendStatusToBrowser | |
105 void HexGameInstance::SendStatusToBrowser() { | |
106 fprintf(stderr, "Entered SendStatusToBrowser\n"); | |
107 if (!sent_game_loop_ready_ && game_loop_ready_) { | |
108 fprintf(stderr, "Sending GameLoopReady!\n"); | |
109 PostMessage(pp::Var("GAME_LOOP_READY")); | |
110 sent_game_loop_ready_ = true; | |
111 return; | |
112 } | |
113 if (last_move_was_invalid_) { | |
114 fprintf(stderr, "invalid move...\n"); | |
115 PostMessage(pp::Var("INVALIDMOVE")); | |
116 return; | |
117 } | |
118 if (user_wins_) { | |
119 fprintf(stderr, "game over...\n"); | |
120 GameOver(); | |
121 return; | |
122 } | |
123 fprintf(stderr, "computer move...\n"); | |
124 std::stringstream oss; | |
125 oss << "COMPUTERMOVE: " << computer_column_ << "," << computer_row_; | |
126 printf("Calling PostMessage with [%s]\n", oss.str().c_str()); | |
127 PostMessage(pp::Var(oss.str())); | |
128 fprintf(stderr, "sent computer move...\n"); | |
129 | |
130 // check for computer win here, because if the computer had a last | |
131 // move that wasn't yet sent to the browser, we want to send that | |
132 // move before declaring that the computer is the winner. | |
133 if (computer_wins_) { | |
134 fprintf(stderr, "game over...\n"); | |
135 GameOver(); | |
136 return; | |
137 } | |
138 } | |
139 | |
140 void HexGameInstance::SetComputerMove(uint32_t col, uint32_t row) { | |
141 computer_column_ = col; | |
142 computer_row_ = row; | |
143 } | |
144 | |
145 void UpdateCallback(void* data, int32_t /*result*/) { | |
146 fprintf(stderr, "UpdateCallback is calling Update\n"); | |
147 HexGameInstance* hex_instance = static_cast<HexGameInstance*>(data); | |
148 hex_instance->SendStatusToBrowser(); | |
149 // fprintf(stderr, "EXITED UpdateCallback\n"); | |
150 } | |
151 | |
152 bool HexGameInstance::Init(uint32_t argc, const char* argn[], | |
153 const char* argv[]) { | |
154 pthread_create(&compute_pi_thread_, NULL, AppMain, this); | |
155 return true; | |
156 } | |
157 | |
158 // Called when the NEXE gets a message from Javascript | |
159 void HexGameInstance::HandleMessage(const pp::Var& var_message) { | |
160 if (!var_message.is_string()) { | |
161 printf("RETURNING from HandleMessage -- var_message is NOT a STRING!\n"); | |
162 return; | |
163 } | |
164 std::string message = var_message.AsString(); | |
165 printf("HANDLE_MESSAGE received {%s}\n", message.c_str()); | |
166 | |
167 std::vector<std::string> words; | |
168 GetElementsFromString(message, std::string(": "), words); | |
169 | |
170 if (words[0] == "USERMOVE" && words.size() >= 3) { | |
171 int col = atoi(words[1].c_str()); | |
172 int row = atoi(words[2].c_str()); | |
173 printf("USERMOVE column %d row %d\n", col, row); | |
174 | |
175 UserMove u(col, row); | |
176 event_queue_.Push(u); | |
177 return; | |
178 } | |
179 } | |
180 | |
181 } // namespace | |
182 | |
183 namespace pp { | |
184 /// Factory function called by the browser when the module is first loaded. | |
185 /// The browser keeps a singleton of this module. It calls the | |
186 /// CreateInstance() method on the object you return to make instances. There | |
187 /// is one instance per <embed> tag on the page. This is the main binding | |
188 /// point for your NaCl module with the browser. | |
189 /// @return new HexGameModule. | |
190 /// @note The browser is responsible for deleting returned @a Module. | |
191 Module* CreateModule() { | |
192 return new hexgame::HexGameModule(); | |
193 } | |
194 } // namespace pp | |
195 | |
OLD | NEW |