chrisgregan
9 years ago
93 changed files with 27980 additions and 4 deletions
@ -1,7 +1,7 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 281dd8265cd4c4d00b1c5ad04f2e6b5a |
||||
guid: 6fb32c987f2084f71b3394b6efb57ccf |
||||
folderAsset: yes |
||||
timeCreated: 1458814154 |
||||
timeCreated: 1455641608 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
@ -1,7 +1,7 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 7b5a2e9e9c22f479480e7cf72064bffa |
||||
guid: b08784ce29a474b758098629a00fb6c4 |
||||
folderAsset: yes |
||||
timeCreated: 1439214867 |
||||
timeCreated: 1454684130 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 0319726c027694d388d69066da479b61 |
||||
timeCreated: 1457363324 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: f739410aaa44d4fbca15e7fee5842e50 |
||||
timeCreated: 1457362432 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: ad95753a2eeea4611980e3a03ebd8826 |
||||
folderAsset: yes |
||||
timeCreated: 1455555043 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 479e25ea74c6e467f80ffa29bb049e0d |
||||
folderAsset: yes |
||||
timeCreated: 1454938226 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,258 @@
|
||||
local inspect = require('inspect') |
||||
|
||||
-- Utility functions for working with Lua in Fungus |
||||
local M = {} |
||||
|
||||
------------ |
||||
-- Debugging |
||||
------------ |
||||
|
||||
function M.inspect(v) |
||||
print (inspect.inspect(v)) |
||||
end |
||||
|
||||
------- |
||||
-- Time |
||||
------- |
||||
|
||||
-- Returns the absolute time |
||||
-- Use this timing function to work correctly with the FungusScript timeScale property |
||||
function M.time() |
||||
return unity.fungusscript.getTime() |
||||
end |
||||
|
||||
-- Returns the delta time this frame |
||||
-- Use this timing function to work correctly with the FungusScript timeScale property |
||||
function M.deltatime() |
||||
return unity.fungusscript.getDeltaTime() |
||||
end |
||||
|
||||
------------- |
||||
-- Coroutines |
||||
------------- |
||||
|
||||
-- Waits for a number of seconds |
||||
function M.wait(duration) |
||||
local t = M.time() |
||||
while (M.time() - t < duration) do |
||||
coroutine.yield() |
||||
end |
||||
end |
||||
|
||||
-- Waits until the lamda function provided returns true, or the timeout expires. |
||||
-- Returns true if the function succeeded, or false if the timeout expired |
||||
-- |
||||
function M.waitfor(fn, timeoutDuration) |
||||
local t = M.time() |
||||
while (not fn()) do |
||||
coroutine.yield() |
||||
if (M.time() - t > timeoutDuration) then |
||||
return false |
||||
end |
||||
end |
||||
return true |
||||
end |
||||
|
||||
-- Starts a C# coroutine method |
||||
function M.run(enumerator) |
||||
-- If the parameter isn't an enumerator then CreateTask will fail |
||||
local status, err = pcall( function() |
||||
local task = unity.fungusscript.RunUnityCoroutine(enumerator) |
||||
end) |
||||
|
||||
if (not status) then |
||||
print(debug.traceback("Can't start a coroutine with a c# method that doesn't return IEnumerator", 2)) |
||||
error(err) |
||||
end |
||||
end |
||||
|
||||
-- Starts a C# coroutine method and waits until it's finished |
||||
function M.runwait(enumerator) |
||||
-- If the parameter isn't an enumerator then CreateTask will fail |
||||
local status, err = pcall( function() |
||||
local task = unity.fungusscript.RunUnityCoroutine(enumerator) |
||||
while (task != nil and task.Running) do |
||||
coroutine.yield(); |
||||
end |
||||
end) |
||||
|
||||
if (not status) then |
||||
print(debug.traceback("Can't start a coroutine with a c# method that doesn't return IEnumerator", 2)) |
||||
error(err) |
||||
end |
||||
end |
||||
|
||||
--------------- |
||||
-- String table |
||||
--------------- |
||||
|
||||
-- Set active language for string table |
||||
function M.setlanguage(languageCode) |
||||
unity.fungusscript.activeLanguage = languageCode |
||||
end |
||||
|
||||
-- Get a named string from the string table |
||||
function M.getstring(key) |
||||
return unity.fungusscript.GetString(key) |
||||
end |
||||
|
||||
-- Substitutes variables and localisation strings into a piece of text |
||||
-- e.g. v = 10, "Subbed value is [$v]" => "Subbed value is 10" |
||||
function M.sub(text) |
||||
return unity.fungusscript.substitute(text) |
||||
end |
||||
|
||||
-------------------- |
||||
-- Integration tests |
||||
-------------------- |
||||
|
||||
-- Assert a condition is true (requires Unity Test Tools) |
||||
function M.assert(c, reason) |
||||
if (not c) then |
||||
-- Output a traceback to help track down source |
||||
error( debug.traceback("Assert failed", 2) ) |
||||
end |
||||
unity.test.assert(c, reason) |
||||
end |
||||
|
||||
-- Pass an integration test (requires Unity Test Tools) |
||||
function M.pass() |
||||
unity.test.pass() |
||||
end |
||||
|
||||
-- Fail an integration test (requires Unity Test Tools) |
||||
function M.fail(reason) |
||||
error( debug.traceback("Test failed", 2) ) |
||||
unity.test.fail(reason) |
||||
end |
||||
|
||||
--------------- |
||||
-- Fungus Prefs |
||||
--------------- |
||||
|
||||
-- prefs is a handy short alias to the real fungusprefs |
||||
M.prefs = unity.fungusprefs |
||||
|
||||
------------- |
||||
-- Say Dialog |
||||
------------- |
||||
|
||||
-- Options for configuring Say Dialog behaviour |
||||
M.sayoptions = {} |
||||
M.sayoptions.saydialog = nil |
||||
M.sayoptions.clearprevious = true |
||||
M.sayoptions.waitforinput = true |
||||
M.sayoptions.fadewhendone = true |
||||
M.sayoptions.stopvoiceover = true |
||||
|
||||
-- Set the active saydialog to use with the say function |
||||
function M.setsaydialog(saydialog) |
||||
M.sayoptions.saydialog = saydialog |
||||
end |
||||
|
||||
-- Set the active character on the Say Dialog |
||||
-- character: A Fungus.Character component |
||||
-- portrait: The name of a sprite in the character's portrait list |
||||
function M.setcharacter(character, portrait) |
||||
assert(character, "character must not be nil") |
||||
assert(M.sayoptions.saydialog, "saydialog must not be nil") |
||||
M.sayoptions.saydialog.SetCharacter(character) |
||||
|
||||
-- Do substitution on character name |
||||
local subbed = fungus.sub(character.nameText) |
||||
M.sayoptions.saydialog.SetCharacterName(subbed, character.nameColor) |
||||
|
||||
-- Try to set the portrait sprite |
||||
if (portrait) then |
||||
if (portrait == "") then |
||||
M.sayoptions.saydialog.SetCharacterImage(nill) |
||||
else |
||||
for i,v in ipairs(character.portraits) do |
||||
-- Use a case insensitive comparison |
||||
if (string.lower(v.name) == string.lower(portrait)) then |
||||
M.sayoptions.saydialog.SetCharacterImage(v) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Write text to the active Say Dialog |
||||
-- text: A string to write to the say dialog |
||||
-- voice: A voiceover audioclip to play |
||||
function M.say(text, voiceclip) |
||||
assert(M.sayoptions.saydialog, "saydialog must not be nil") |
||||
|
||||
-- Do variable substitution before displaying text |
||||
local subbed = fungus.sub(text) |
||||
local e = M.sayoptions.saydialog.SayInternal(subbed, M.sayoptions.clearprevious, M.sayoptions.waitforinput, M.sayoptions.fadewhendone, M.sayoptions.stopvoiceover, voiceclip) |
||||
|
||||
fungus.runwait(e) |
||||
end |
||||
|
||||
-------------- |
||||
-- Menu Dialog |
||||
-------------- |
||||
|
||||
-- Options for configuring Menu Dialog behaviour |
||||
M.menuoptions = {} |
||||
|
||||
-- Set the active menudialog to use with the menu function |
||||
function M.setmenudialog(menudialog) |
||||
M.menuoptions.menudialog = menudialog |
||||
end |
||||
|
||||
-- Display a menu button |
||||
-- text: text to display on the button |
||||
-- callback: function to call when this option is selected |
||||
-- interactive (optional): if false, displays the option as disabled |
||||
function M.menu(text, callback, interactive) |
||||
assert(M.menuoptions.menudialog, "menudialog must not be nil") |
||||
|
||||
-- Do variable substitution before displaying text |
||||
local subbed = fungus.sub(text) |
||||
M.menuoptions.menudialog.AddOption(subbed, interactive or true, unity.fungusscript, callback) |
||||
end |
||||
|
||||
-- Display a timer during which the player has to choose an option. |
||||
-- duration: The length of time to display the timer. |
||||
-- callback: Function to call if the timer expires before an option is selected. |
||||
function M.menutimer(duration, callback) |
||||
assert(M.menuoptions.menudialog, "menudialog must not be nil") |
||||
local e = M.menuoptions.menudialog.ShowTimer(duration, unity.fungusscript, callback) |
||||
fungus.runwait(e) |
||||
end |
||||
|
||||
-- Clear all currently displayed menu options |
||||
function M.clearmenu() |
||||
assert(M.menuoptions.menudialog, "menudialog must not be nil") |
||||
M.menuoptions.menudialog.Clear() |
||||
end |
||||
|
||||
------------ |
||||
-- Flowchart |
||||
------------ |
||||
|
||||
-- Runs the specified Block in a Flowchart |
||||
-- flowchart: The Fungus Flowchart containing the Block to run. |
||||
-- blockname: The name of the Block to run. |
||||
-- nowait: If false, will yield until the Block finishes execution. If true will continue immediately. |
||||
function M.runblock(flowchart, blockname, nowait) |
||||
assert(flowchart, "flowchart must not be nil") |
||||
assert(blockname, "blockname must not be nil") |
||||
local block = flowchart.FindBlock(blockname) |
||||
if (not block) then |
||||
error("Block " .. blockname .. " not found") |
||||
return |
||||
end |
||||
|
||||
local e = block.Execute(); |
||||
|
||||
if (nowait) then |
||||
M.run( e ) |
||||
else |
||||
M.runwait( e ) |
||||
end |
||||
end |
||||
|
||||
return M |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: d189f86f383a341ac8dcfe22cb6309a1 |
||||
timeCreated: 1458919194 |
||||
licenseType: Free |
||||
TextScriptImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,331 @@
|
||||
local inspect ={ |
||||
_VERSION = 'inspect.lua 3.0.2', |
||||
_URL = 'http://github.com/kikito/inspect.lua', |
||||
_DESCRIPTION = 'human-readable representations of tables', |
||||
_LICENSE = [[ |
||||
MIT LICENSE |
||||
|
||||
Copyright (c) 2013 Enrique García Cota |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the |
||||
"Software"), to deal in the Software without restriction, including |
||||
without limitation the rights to use, copy, modify, merge, publish, |
||||
distribute, sublicense, and/or sell copies of the Software, and to |
||||
permit persons to whom the Software is furnished to do so, subject to |
||||
the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
]] |
||||
} |
||||
|
||||
inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) |
||||
inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) |
||||
|
||||
-- returns the length of a table, ignoring __len (if it exists) |
||||
local rawlen = _G.rawlen or function(t) return #t end |
||||
|
||||
-- Apostrophizes the string if it has quotes, but not aphostrophes |
||||
-- Otherwise, it returns a regular quoted string |
||||
local function smartQuote(str) |
||||
if str:match('"') and not str:match("'") then |
||||
return "'" .. str .. "'" |
||||
end |
||||
return '"' .. str:gsub('"', '\\"') .. '"' |
||||
end |
||||
|
||||
local controlCharsTranslation = { |
||||
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", |
||||
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" |
||||
} |
||||
|
||||
local function escape(str) |
||||
local result = str:gsub("\\", "\\\\"):gsub("(%c)", controlCharsTranslation) |
||||
return result |
||||
end |
||||
|
||||
local function isIdentifier(str) |
||||
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) |
||||
end |
||||
|
||||
local function isSequenceKey(k, length) |
||||
return type(k) == 'number' |
||||
and 1 <= k |
||||
and k <= length |
||||
and math.floor(k) == k |
||||
end |
||||
|
||||
local defaultTypeOrders = { |
||||
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, |
||||
['function'] = 5, ['userdata'] = 6, ['thread'] = 7 |
||||
} |
||||
|
||||
local function sortKeys(a, b) |
||||
local ta, tb = type(a), type(b) |
||||
|
||||
-- strings and numbers are sorted numerically/alphabetically |
||||
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end |
||||
|
||||
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] |
||||
-- Two default types are compared according to the defaultTypeOrders table |
||||
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] |
||||
elseif dta then return true -- default types before custom ones |
||||
elseif dtb then return false -- custom types after default ones |
||||
end |
||||
|
||||
-- custom types are sorted out alphabetically |
||||
return ta < tb |
||||
end |
||||
|
||||
local function getNonSequentialKeys(t) |
||||
local keys, length = {}, rawlen(t) |
||||
for k,_ in pairs(t) do |
||||
if not isSequenceKey(k, length) then table.insert(keys, k) end |
||||
end |
||||
table.sort(keys, sortKeys) |
||||
return keys |
||||
end |
||||
|
||||
local function getToStringResultSafely(t, mt) |
||||
local __tostring = type(mt) == 'table' and rawget(mt, '__tostring') |
||||
local str, ok |
||||
if type(__tostring) == 'function' then |
||||
ok, str = pcall(__tostring, t) |
||||
str = ok and str or 'error: ' .. tostring(str) |
||||
end |
||||
if type(str) == 'string' and #str > 0 then return str end |
||||
end |
||||
|
||||
local maxIdsMetaTable = { |
||||
__index = function(self, typeName) |
||||
rawset(self, typeName, 0) |
||||
return 0 |
||||
end |
||||
} |
||||
|
||||
local idsMetaTable = { |
||||
__index = function (self, typeName) |
||||
local col = {} |
||||
rawset(self, typeName, col) |
||||
return col |
||||
end |
||||
} |
||||
|
||||
local function countTableAppearances(t, tableAppearances) |
||||
tableAppearances = tableAppearances or {} |
||||
|
||||
if type(t) == 'table' then |
||||
if not tableAppearances[t] then |
||||
tableAppearances[t] = 1 |
||||
for k,v in pairs(t) do |
||||
countTableAppearances(k, tableAppearances) |
||||
countTableAppearances(v, tableAppearances) |
||||
end |
||||
countTableAppearances(getmetatable(t), tableAppearances) |
||||
else |
||||
tableAppearances[t] = tableAppearances[t] + 1 |
||||
end |
||||
end |
||||
|
||||
return tableAppearances |
||||
end |
||||
|
||||
local copySequence = function(s) |
||||
local copy, len = {}, #s |
||||
for i=1, len do copy[i] = s[i] end |
||||
return copy, len |
||||
end |
||||
|
||||
local function makePath(path, ...) |
||||
local keys = {...} |
||||
local newPath, len = copySequence(path) |
||||
for i=1, #keys do |
||||
newPath[len + i] = keys[i] |
||||
end |
||||
return newPath |
||||
end |
||||
|
||||
local function processRecursive(process, item, path) |
||||
if item == nil then return nil end |
||||
|
||||
local processed = process(item, path) |
||||
if type(processed) == 'table' then |
||||
local processedCopy = {} |
||||
local processedKey |
||||
|
||||
for k,v in pairs(processed) do |
||||
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY)) |
||||
if processedKey ~= nil then |
||||
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey)) |
||||
end |
||||
end |
||||
|
||||
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE)) |
||||
setmetatable(processedCopy, mt) |
||||
processed = processedCopy |
||||
end |
||||
return processed |
||||
end |
||||
|
||||
|
||||
------------------------------------------------------------------- |
||||
|
||||
local Inspector = {} |
||||
local Inspector_mt = {__index = Inspector} |
||||
|
||||
function Inspector:puts(...) |
||||
local args = {...} |
||||
local buffer = self.buffer |
||||
local len = #buffer |
||||
for i=1, #args do |
||||
len = len + 1 |
||||
buffer[len] = tostring(args[i]) |
||||
end |
||||
end |
||||
|
||||
function Inspector:down(f) |
||||
self.level = self.level + 1 |
||||
f() |
||||
self.level = self.level - 1 |
||||
end |
||||
|
||||
function Inspector:tabify() |
||||
self:puts(self.newline, string.rep(self.indent, self.level)) |
||||
end |
||||
|
||||
function Inspector:alreadyVisited(v) |
||||
return self.ids[type(v)][v] ~= nil |
||||
end |
||||
|
||||
function Inspector:getId(v) |
||||
local tv = type(v) |
||||
local id = self.ids[tv][v] |
||||
if not id then |
||||
id = self.maxIds[tv] + 1 |
||||
self.maxIds[tv] = id |
||||
self.ids[tv][v] = id |
||||
end |
||||
return id |
||||
end |
||||
|
||||
function Inspector:putKey(k) |
||||
if isIdentifier(k) then return self:puts(k) end |
||||
self:puts("[") |
||||
self:putValue(k) |
||||
self:puts("]") |
||||
end |
||||
|
||||
function Inspector:putTable(t) |
||||
if t == inspect.KEY or t == inspect.METATABLE then |
||||
self:puts(tostring(t)) |
||||
elseif self:alreadyVisited(t) then |
||||
self:puts('<table ', self:getId(t), '>') |
||||
elseif self.level >= self.depth then |
||||
self:puts('{...}') |
||||
else |
||||
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end |
||||
|
||||
local nonSequentialKeys = getNonSequentialKeys(t) |
||||
local length = rawlen(t) |
||||
local mt = getmetatable(t) |
||||
local toStringResult = getToStringResultSafely(t, mt) |
||||
|
||||
self:puts('{') |
||||
self:down(function() |
||||
if toStringResult then |
||||
self:puts(' -- ', escape(toStringResult)) |
||||
if length >= 1 then self:tabify() end |
||||
end |
||||
|
||||
local count = 0 |
||||
for i=1, length do |
||||
if count > 0 then self:puts(',') end |
||||
self:puts(' ') |
||||
self:putValue(t[i]) |
||||
count = count + 1 |
||||
end |
||||
|
||||
for _,k in ipairs(nonSequentialKeys) do |
||||
if count > 0 then self:puts(',') end |
||||
self:tabify() |
||||
self:putKey(k) |
||||
self:puts(' = ') |
||||
self:putValue(t[k]) |
||||
count = count + 1 |
||||
end |
||||
|
||||
if mt then |
||||
if count > 0 then self:puts(',') end |
||||
self:tabify() |
||||
self:puts('<metatable> = ') |
||||
self:putValue(mt) |
||||
end |
||||
end) |
||||
|
||||
if #nonSequentialKeys > 0 or mt then -- result is multi-lined. Justify closing } |
||||
self:tabify() |
||||
elseif length > 0 then -- array tables have one extra space before closing } |
||||
self:puts(' ') |
||||
end |
||||
|
||||
self:puts('}') |
||||
end |
||||
end |
||||
|
||||
function Inspector:putValue(v) |
||||
local tv = type(v) |
||||
|
||||
if tv == 'string' then |
||||
self:puts(smartQuote(escape(v))) |
||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then |
||||
self:puts(tostring(v)) |
||||
elseif tv == 'table' then |
||||
self:putTable(v) |
||||
else |
||||
self:puts('<',tv,' ',self:getId(v),'>') |
||||
end |
||||
end |
||||
|
||||
------------------------------------------------------------------- |
||||
|
||||
function inspect.inspect(root, options) |
||||
options = options or {} |
||||
|
||||
local depth = options.depth or math.huge |
||||
local newline = options.newline or '\n' |
||||
local indent = options.indent or ' ' |
||||
local process = options.process |
||||
|
||||
if process then |
||||
root = processRecursive(process, root, {}) |
||||
end |
||||
|
||||
local inspector = setmetatable({ |
||||
depth = depth, |
||||
buffer = {}, |
||||
level = 0, |
||||
ids = setmetatable({}, idsMetaTable), |
||||
maxIds = setmetatable({}, maxIdsMetaTable), |
||||
newline = newline, |
||||
indent = indent, |
||||
tableAppearances = countTableAppearances(root) |
||||
}, Inspector_mt) |
||||
|
||||
inspector:putValue(root) |
||||
|
||||
return table.concat(inspector.buffer) |
||||
end |
||||
|
||||
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) |
||||
|
||||
return inspect |
||||
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 05e8903e53b464591b902273f0a3cf3d |
||||
timeCreated: 1456487108 |
||||
licenseType: Free |
||||
TextScriptImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 94ca1ff98b1a144009c9c9d9977fbe95 |
||||
folderAsset: yes |
||||
timeCreated: 1456135684 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,55 @@
|
||||
%YAML 1.1 |
||||
%TAG !u! tag:unity3d.com,2011: |
||||
--- !u!1 &178698 |
||||
GameObject: |
||||
m_ObjectHideFlags: 0 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
serializedVersion: 4 |
||||
m_Component: |
||||
- 4: {fileID: 403334} |
||||
- 114: {fileID: 11414792} |
||||
m_Layer: 0 |
||||
m_Name: FungusBindings |
||||
m_TagString: Untagged |
||||
m_Icon: {fileID: 0} |
||||
m_NavMeshLayer: 0 |
||||
m_StaticEditorFlags: 0 |
||||
m_IsActive: 1 |
||||
--- !u!4 &403334 |
||||
Transform: |
||||
m_ObjectHideFlags: 1 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
m_GameObject: {fileID: 178698} |
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} |
||||
m_LocalPosition: {x: 0, y: 0, z: 0} |
||||
m_LocalScale: {x: 1, y: 1, z: 1} |
||||
m_Children: [] |
||||
m_Father: {fileID: 0} |
||||
m_RootOrder: 0 |
||||
--- !u!114 &11414792 |
||||
MonoBehaviour: |
||||
m_ObjectHideFlags: 1 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
m_GameObject: {fileID: 178698} |
||||
m_Enabled: 1 |
||||
m_EditorHideFlags: 0 |
||||
m_Script: {fileID: 11500000, guid: 4cc8a659e950044b69d7c62696c36962, type: 3} |
||||
m_Name: |
||||
m_EditorClassIdentifier: |
||||
tableName: |
||||
boundObjects: [] |
||||
boundTypes: [] |
||||
--- !u!1001 &100100000 |
||||
Prefab: |
||||
m_ObjectHideFlags: 1 |
||||
serializedVersion: 2 |
||||
m_Modification: |
||||
m_TransformParent: {fileID: 0} |
||||
m_Modifications: [] |
||||
m_RemovedComponents: [] |
||||
m_ParentPrefab: {fileID: 0} |
||||
m_RootGameObject: {fileID: 178698} |
||||
m_IsPrefabParent: 1 |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: e0c2b90c058ff43f4a56a266d4fa721b |
||||
timeCreated: 1455234100 |
||||
licenseType: Free |
||||
NativeFormatImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,65 @@
|
||||
%YAML 1.1 |
||||
%TAG !u! tag:unity3d.com,2011: |
||||
--- !u!1 &139298 |
||||
GameObject: |
||||
m_ObjectHideFlags: 0 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
serializedVersion: 4 |
||||
m_Component: |
||||
- 4: {fileID: 449874} |
||||
- 114: {fileID: 11472914} |
||||
m_Layer: 0 |
||||
m_Name: FungusInvoke |
||||
m_TagString: Untagged |
||||
m_Icon: {fileID: 0} |
||||
m_NavMeshLayer: 0 |
||||
m_StaticEditorFlags: 0 |
||||
m_IsActive: 1 |
||||
--- !u!4 &449874 |
||||
Transform: |
||||
m_ObjectHideFlags: 1 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
m_GameObject: {fileID: 139298} |
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} |
||||
m_LocalPosition: {x: 0, y: 0, z: 0} |
||||
m_LocalScale: {x: 1, y: 1, z: 1} |
||||
m_Children: [] |
||||
m_Father: {fileID: 0} |
||||
m_RootOrder: 0 |
||||
--- !u!114 &11472914 |
||||
MonoBehaviour: |
||||
m_ObjectHideFlags: 1 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
m_GameObject: {fileID: 139298} |
||||
m_Enabled: 1 |
||||
m_EditorHideFlags: 0 |
||||
m_Script: {fileID: 11500000, guid: 446caeace65234baaacd52095d24f101, type: 3} |
||||
m_Name: |
||||
m_EditorClassIdentifier: |
||||
executeAfterTime: 1 |
||||
repeatExecuteTime: 1 |
||||
repeatEveryTime: 1 |
||||
executeAfterFrames: 1 |
||||
repeatExecuteFrame: 1 |
||||
repeatEveryFrame: 1 |
||||
hasFailed: 0 |
||||
executeMethods: 2 |
||||
fungusScript: {fileID: 0} |
||||
luaFile: {fileID: 0} |
||||
luaScript: |
||||
runAsCoroutine: 1 |
||||
useFungusModule: 1 |
||||
--- !u!1001 &100100000 |
||||
Prefab: |
||||
m_ObjectHideFlags: 1 |
||||
serializedVersion: 2 |
||||
m_Modification: |
||||
m_TransformParent: {fileID: 0} |
||||
m_Modifications: [] |
||||
m_RemovedComponents: [] |
||||
m_ParentPrefab: {fileID: 0} |
||||
m_RootGameObject: {fileID: 139298} |
||||
m_IsPrefabParent: 1 |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: c356764ac08ce4af2806a601a4f1e6e9 |
||||
timeCreated: 1456135721 |
||||
licenseType: Free |
||||
NativeFormatImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,56 @@
|
||||
%YAML 1.1 |
||||
%TAG !u! tag:unity3d.com,2011: |
||||
--- !u!1 &100640 |
||||
GameObject: |
||||
m_ObjectHideFlags: 0 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
serializedVersion: 4 |
||||
m_Component: |
||||
- 4: {fileID: 495584} |
||||
- 114: {fileID: 11493126} |
||||
m_Layer: 0 |
||||
m_Name: FungusScript |
||||
m_TagString: Untagged |
||||
m_Icon: {fileID: 0} |
||||
m_NavMeshLayer: 0 |
||||
m_StaticEditorFlags: 0 |
||||
m_IsActive: 1 |
||||
--- !u!4 &495584 |
||||
Transform: |
||||
m_ObjectHideFlags: 1 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
m_GameObject: {fileID: 100640} |
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} |
||||
m_LocalPosition: {x: 0, y: 0, z: 0} |
||||
m_LocalScale: {x: 1, y: 1, z: 1} |
||||
m_Children: [] |
||||
m_Father: {fileID: 0} |
||||
m_RootOrder: 0 |
||||
--- !u!114 &11493126 |
||||
MonoBehaviour: |
||||
m_ObjectHideFlags: 1 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 100100000} |
||||
m_GameObject: {fileID: 100640} |
||||
m_Enabled: 1 |
||||
m_EditorHideFlags: 0 |
||||
m_Script: {fileID: 11500000, guid: ba19c26c1ba7243d2b57ebc4329cc7c6, type: 3} |
||||
m_Name: |
||||
m_EditorClassIdentifier: |
||||
remoteDebugger: 0 |
||||
stringTable: {fileID: 0} |
||||
activeLanguage: en |
||||
timeScale: -1 |
||||
--- !u!1001 &100100000 |
||||
Prefab: |
||||
m_ObjectHideFlags: 1 |
||||
serializedVersion: 2 |
||||
m_Modification: |
||||
m_TransformParent: {fileID: 0} |
||||
m_Modifications: [] |
||||
m_RemovedComponents: [] |
||||
m_ParentPrefab: {fileID: 0} |
||||
m_RootGameObject: {fileID: 100640} |
||||
m_IsPrefabParent: 1 |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 49031c561e16d4fcf91c12153f8e0b25 |
||||
timeCreated: 1455036757 |
||||
licenseType: Free |
||||
NativeFormatImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: faeb3c27132254942b6ffd5acf46da3a |
||||
folderAsset: yes |
||||
timeCreated: 1454683902 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 2f151bb1b31334ecea7f682307a2d687 |
||||
folderAsset: yes |
||||
timeCreated: 1454428088 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,81 @@
|
||||
// Adapted from the Unity Test Tools project (MIT license) |
||||
// https://bitbucket.org/Unity-Technologies/unitytesttools/src/a30d562427e9/Assets/UnityTestTools/ |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using UnityEditor; |
||||
using UnityEngine; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
[Serializable] |
||||
internal class DropDownControl<T> |
||||
{ |
||||
private readonly GUILayoutOption[] m_ButtonLayoutOptions = { GUILayout.ExpandWidth(true) }; |
||||
public Func<T, string> convertForButtonLabel = s => s.ToString(); |
||||
public Func<T, string> convertForGUIContent = s => s.ToString(); |
||||
public Func<T[], bool> ignoreConvertForGUIContent = t => t.Length <= 40; |
||||
public Action<T> printContextMenu = null; |
||||
public string tooltip = ""; |
||||
|
||||
private object m_SelectedValue; |
||||
|
||||
|
||||
public void Draw(T selected, T[] options, Action<T> onValueSelected) |
||||
{ |
||||
Draw(null, |
||||
selected, |
||||
options, |
||||
onValueSelected); |
||||
} |
||||
|
||||
public void Draw(string label, T selected, T[] options, Action<T> onValueSelected) |
||||
{ |
||||
Draw(label, selected, () => options, onValueSelected); |
||||
} |
||||
|
||||
public void Draw(string label, T selected, Func<T[]> loadOptions, Action<T> onValueSelected) |
||||
{ |
||||
if (!string.IsNullOrEmpty(label)) |
||||
EditorGUILayout.BeginHorizontal(); |
||||
var guiContent = new GUIContent(label); |
||||
var labelSize = EditorStyles.label.CalcSize(guiContent); |
||||
|
||||
if (!string.IsNullOrEmpty(label)) |
||||
GUILayout.Label(label, EditorStyles.label, GUILayout.Width(labelSize.x)); |
||||
|
||||
if (GUILayout.Button(new GUIContent(convertForButtonLabel(selected), tooltip), |
||||
EditorStyles.popup, m_ButtonLayoutOptions)) |
||||
{ |
||||
if (Event.current.button == 0) |
||||
{ |
||||
PrintMenu(loadOptions()); |
||||
} |
||||
else if (printContextMenu != null && Event.current.button == 1) |
||||
printContextMenu(selected); |
||||
} |
||||
|
||||
if (m_SelectedValue != null) |
||||
{ |
||||
onValueSelected((T)m_SelectedValue); |
||||
m_SelectedValue = null; |
||||
} |
||||
if (!string.IsNullOrEmpty(label)) |
||||
EditorGUILayout.EndHorizontal(); |
||||
} |
||||
|
||||
public void PrintMenu(T[] options) |
||||
{ |
||||
var menu = new GenericMenu(); |
||||
foreach (var s in options) |
||||
{ |
||||
var localS = s; |
||||
menu.AddItem(new GUIContent((ignoreConvertForGUIContent(options) ? localS.ToString() : convertForGUIContent(localS))), |
||||
false, |
||||
() => { m_SelectedValue = localS; } |
||||
); |
||||
} |
||||
menu.ShowAsContext(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 62435b27e6a904bd99a8ce6e38f05445 |
||||
timeCreated: 1455233914 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,455 @@
|
||||
using UnityEditor; |
||||
using UnityEditorInternal; |
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using Rotorz.ReorderableList; |
||||
using System.Linq; |
||||
using System.Reflection; |
||||
using System.IO; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
[CustomEditor (typeof(FungusBindings))] |
||||
public class FungusBindingsEditor : Editor |
||||
{ |
||||
protected ReorderableList boundObjectsList; |
||||
|
||||
protected SerializedProperty tableNameProp; |
||||
protected SerializedProperty boundObjectsProp; |
||||
|
||||
protected string bindingHelpItem = ""; |
||||
protected string bindingHelpDetail = ""; |
||||
|
||||
protected virtual void OnEnable() |
||||
{ |
||||
tableNameProp = serializedObject.FindProperty("tableName"); |
||||
boundObjectsProp = serializedObject.FindProperty("boundObjects"); |
||||
CreateBoundObjectsList(); |
||||
} |
||||
|
||||
protected void CreateBoundObjectsList() |
||||
{ |
||||
boundObjectsList = new ReorderableList(serializedObject, boundObjectsProp, true, true, true, true); |
||||
|
||||
boundObjectsList.drawElementCallback = |
||||
(Rect rect, int index, bool isActive, bool isFocused) => { |
||||
var element = boundObjectsList.serializedProperty.GetArrayElementAtIndex(index); |
||||
rect.y += 2; |
||||
|
||||
float widthA = rect.width * 0.25f; |
||||
float widthB = rect.width * 0.75f * 0.5f; |
||||
float widthC = rect.width * 0.75f * 0.5f; |
||||
|
||||
SerializedProperty keyProp = element.FindPropertyRelative("key"); |
||||
SerializedProperty objectProp = element.FindPropertyRelative("obj"); |
||||
|
||||
EditorGUI.BeginChangeCheck(); |
||||
|
||||
EditorGUI.PropertyField( |
||||
new Rect(rect.x, rect.y, widthA - 5, EditorGUIUtility.singleLineHeight), |
||||
keyProp, GUIContent.none); |
||||
|
||||
if (EditorGUI.EndChangeCheck()) |
||||
{ |
||||
// Force the key to be a valid Lua variable name |
||||
FungusBindings fungusBindings = target as FungusBindings; |
||||
keyProp.stringValue = GetUniqueKey(fungusBindings, keyProp.stringValue, index); |
||||
} |
||||
|
||||
EditorGUI.BeginChangeCheck(); |
||||
|
||||
EditorGUI.PropertyField( |
||||
new Rect(rect.x + widthA, rect.y, widthB - 5, EditorGUIUtility.singleLineHeight), |
||||
objectProp, GUIContent.none); |
||||
|
||||
if (EditorGUI.EndChangeCheck()) |
||||
{ |
||||
// Use the object name as the key |
||||
string keyName = objectProp.objectReferenceValue.name; |
||||
FungusBindings fungusBindings = target as FungusBindings; |
||||
element.FindPropertyRelative("key").stringValue = GetUniqueKey(fungusBindings, keyName.ToLower(), index); |
||||
} |
||||
|
||||
if (objectProp.objectReferenceValue != null) |
||||
{ |
||||
GameObject go = objectProp.objectReferenceValue as GameObject; |
||||
if (go != null) |
||||
{ |
||||
SerializedProperty componentProp = element.FindPropertyRelative("component"); |
||||
|
||||
int selected = 0; |
||||
List<string> options = new List<string>(); |
||||
options.Add("<GameObject>"); |
||||
|
||||
int count = 1; |
||||
Component[] componentList = go.GetComponents<Component>(); |
||||
foreach (Component component in componentList) |
||||
{ |
||||
if (componentProp.objectReferenceValue == component) |
||||
{ |
||||
selected = count; |
||||
} |
||||
|
||||
string componentName = component.GetType().ToString().Replace("UnityEngine.", ""); |
||||
options.Add(componentName); |
||||
|
||||
count++; |
||||
} |
||||
|
||||
int i = EditorGUI.Popup( |
||||
new Rect(rect.x + widthA + widthB, rect.y, widthC, EditorGUIUtility.singleLineHeight), |
||||
selected, |
||||
options.ToArray()); |
||||
if (i == 0) |
||||
{ |
||||
componentProp.objectReferenceValue = null; |
||||
} |
||||
else |
||||
{ |
||||
componentProp.objectReferenceValue = componentList[i - 1]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
boundObjectsList.onAddCallback = (ReorderableList l) => { |
||||
// Add a new item. This copies last item in the list, so clear new items values. |
||||
boundObjectsProp.InsertArrayElementAtIndex(boundObjectsProp.arraySize); |
||||
SerializedProperty newItem = boundObjectsProp.GetArrayElementAtIndex(boundObjectsProp.arraySize - 1); |
||||
newItem.FindPropertyRelative("key").stringValue = ""; |
||||
newItem.FindPropertyRelative("obj").objectReferenceValue = null; |
||||
newItem.FindPropertyRelative("component").objectReferenceValue = null; |
||||
}; |
||||
}; |
||||
|
||||
boundObjectsList.drawHeaderCallback = (Rect rect) => { |
||||
|
||||
float widthA = rect.width * 0.25f; |
||||
float widthB = rect.width * 0.75f * 0.5f; |
||||
float widthC = rect.width * 0.75f * 0.5f; |
||||
|
||||
EditorGUI.LabelField(new Rect(rect.x+ 12, rect.y, widthA, EditorGUIUtility.singleLineHeight), "Key"); |
||||
EditorGUI.LabelField(new Rect(rect.x + widthA + 12, rect.y, widthB, EditorGUIUtility.singleLineHeight), "Object"); |
||||
EditorGUI.LabelField(new Rect(rect.x + widthA + widthB + 6, rect.y, widthC, EditorGUIUtility.singleLineHeight), "Component"); |
||||
}; |
||||
} |
||||
|
||||
public override void OnInspectorGUI() |
||||
{ |
||||
serializedObject.Update(); |
||||
|
||||
EditorGUILayout.PropertyField(tableNameProp); |
||||
|
||||
EditorGUILayout.LabelField("Object Bindings"); |
||||
|
||||
boundObjectsList.DoLayoutList(); |
||||
EditorGUILayout.Space(); |
||||
|
||||
ShowBindingMemberInfo(); |
||||
|
||||
// Update the bound types on every tick to make sure they're up to date. |
||||
// This could be a bit heavy on performance if the bound object list is long, but |
||||
// I couldn't get it to work reliably by only updating when the list has changed. |
||||
// This only happens when inspecting a Fungus Bindings component so I think it'll be ok. |
||||
PopulateBoundTypes(); |
||||
|
||||
serializedObject.ApplyModifiedProperties(); |
||||
} |
||||
|
||||
protected virtual void ShowBindingMemberInfo() |
||||
{ |
||||
List<string> items = new List<string>(); |
||||
items.Add("<Select a binding member>"); |
||||
|
||||
List<string> details = new List<string>(); |
||||
details.Add(""); |
||||
|
||||
FungusBindings fungusBindings = target as FungusBindings; |
||||
foreach (FungusBindings.BoundObject boundObject in fungusBindings.boundObjects) |
||||
{ |
||||
UnityEngine.Object inspectObject = boundObject.obj; |
||||
if (boundObject.component != null) |
||||
{ |
||||
inspectObject = boundObject.component; |
||||
} |
||||
|
||||
// Ignore empty entries |
||||
if (inspectObject == null || |
||||
boundObject.key.Length == 0) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Show info for fields and properties |
||||
MemberInfo[] memberInfos = inspectObject.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); |
||||
foreach (MemberInfo memberInfo in memberInfos) |
||||
{ |
||||
if (memberInfo.MemberType != MemberTypes.Field && |
||||
memberInfo.MemberType != MemberTypes.Property) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
string item = boundObject.key + "/" + memberInfo.Name; |
||||
items.Add(item); |
||||
|
||||
string detail = ""; |
||||
detail += "Binding Key: " + boundObject.key + "\n"; |
||||
detail += "Bound Object: " + boundObject.obj.name + "\n"; |
||||
if (boundObject.component != null) |
||||
{ |
||||
detail += "Bound Component: " + boundObject.component.GetType() + "\n"; |
||||
} |
||||
|
||||
if (memberInfo.MemberType == MemberTypes.Field) |
||||
{ |
||||
detail += "Field Name: " + memberInfo.Name + "\n"; |
||||
detail += "Field Type: " + (memberInfo as FieldInfo).FieldType; |
||||
} |
||||
else if (memberInfo.MemberType == MemberTypes.Property) |
||||
{ |
||||
detail += "Property Name: " + memberInfo.Name + "\n"; |
||||
detail += "Property Type: " + (memberInfo as PropertyInfo).PropertyType; |
||||
} |
||||
|
||||
details.Add(detail); |
||||
} |
||||
|
||||
// Show info for methods |
||||
foreach (MemberInfo memberInfo in memberInfos) |
||||
{ |
||||
if (memberInfo.MemberType != MemberTypes.Method) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
MethodInfo methodInfo = memberInfo as MethodInfo; |
||||
if (methodInfo.IsGenericMethod) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Build list of parameters |
||||
string param = ""; |
||||
foreach (ParameterInfo pi in methodInfo.GetParameters() ) |
||||
{ |
||||
if (param == "") |
||||
{ |
||||
param += pi.Name; |
||||
} |
||||
else |
||||
{ |
||||
param += ", " + pi.Name; |
||||
} |
||||
} |
||||
param = "(" + param + ")"; |
||||
|
||||
string item = boundObject.key + "/" + methodInfo.Name + param; |
||||
items.Add(item); |
||||
|
||||
string detail = ""; |
||||
detail += "Binding Key: " + boundObject.key + "\n"; |
||||
detail += "Bound Object: " + boundObject.obj.name + "\n"; |
||||
if (boundObject.component != null) |
||||
{ |
||||
detail += "Bound Component: " + boundObject.component.GetType() + "\n"; |
||||
} |
||||
|
||||
detail += "Method Name: " + methodInfo.Name + "\n"; |
||||
foreach (ParameterInfo pi in methodInfo.GetParameters() ) |
||||
{ |
||||
detail += "Parameter: " + pi.Name + " (" + pi.ParameterType.ToString() + ")\n"; |
||||
} |
||||
detail += "Return Type : " + methodInfo.ReturnType.ToString(); |
||||
|
||||
details.Add(detail); |
||||
} |
||||
} |
||||
|
||||
EditorGUILayout.BeginHorizontal(); |
||||
|
||||
EditorGUILayout.PrefixLabel(new GUIContent("Member Info", "Display member info for the selected binding")); |
||||
|
||||
GUILayout.FlexibleSpace(); |
||||
|
||||
// Display the popup list of bound members |
||||
int selectedIndex = EditorGUILayout.Popup(0, items.ToArray()); |
||||
if (selectedIndex > 0) |
||||
{ |
||||
bindingHelpItem = items[selectedIndex].Replace("/", "."); |
||||
bindingHelpDetail = details[selectedIndex]; |
||||
} |
||||
|
||||
EditorGUILayout.EndHorizontal(); |
||||
|
||||
// Show help info for currently selected item |
||||
if (bindingHelpItem != "") |
||||
{ |
||||
EditorGUILayout.HelpBox(bindingHelpDetail, MessageType.Info); |
||||
|
||||
EditorGUILayout.PrefixLabel(new GUIContent("Lua Usage", "A copyable example of how this item could be used in a Lua script.")); |
||||
|
||||
GUIStyle textAreaStyle = EditorStyles.textField; |
||||
textAreaStyle.wordWrap = true; |
||||
|
||||
EditorGUILayout.TextArea(bindingHelpItem, textAreaStyle, GUILayout.MinHeight(EditorGUIUtility.singleLineHeight * 3)); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a new binding key that is guaranteed to be a valid Lua variable name and |
||||
/// not to clash with any existing binding in the list. |
||||
/// </summary> |
||||
protected virtual string GetUniqueKey(FungusBindings fungusBindings, string originalKey, int ignoreIndex = -1) |
||||
{ |
||||
string baseKey = originalKey; |
||||
|
||||
// Only letters and digits allowed |
||||
char[] arr = baseKey.Where(c => (char.IsLetterOrDigit(c) || c == '_')).ToArray(); |
||||
baseKey = new string(arr); |
||||
|
||||
// No leading digits allowed |
||||
baseKey = baseKey.TrimStart('0','1','2','3','4','5','6','7','8','9'); |
||||
|
||||
// No empty keys allowed |
||||
if (baseKey.Length == 0) |
||||
{ |
||||
baseKey = "object"; |
||||
} |
||||
|
||||
// Build a hash of all keys currently in use |
||||
HashSet<string> keyhash = new HashSet<string>(); |
||||
for (int i = 0; i < fungusBindings.boundObjects.Count; ++i) |
||||
{ |
||||
if (i == ignoreIndex) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
keyhash.Add(fungusBindings.boundObjects[i].key); |
||||
} |
||||
|
||||
// Append a suffix to make the key unique |
||||
string key = baseKey; |
||||
int suffix = 0; |
||||
while (keyhash.Contains(key)) |
||||
{ |
||||
suffix++; |
||||
key = baseKey + suffix; |
||||
} |
||||
|
||||
return key; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Update the list of bound types on the FungusBindings object. |
||||
/// </summary> |
||||
protected virtual void PopulateBoundTypes() |
||||
{ |
||||
FungusBindings fungusBindings = target as FungusBindings; |
||||
|
||||
// Use a temp HashSet to store the list of types. |
||||
// The final list is stored as a list of type strings. |
||||
HashSet<System.Type> typeSet = new HashSet<System.Type>(); |
||||
foreach (FungusBindings.BoundObject boundObject in fungusBindings.boundObjects) |
||||
{ |
||||
if (boundObject.obj == null) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
AddAllSubTypes(typeSet, boundObject.obj.GetType()); |
||||
|
||||
if (boundObject.component != null) |
||||
{ |
||||
AddAllSubTypes(typeSet, boundObject.component.GetType()); |
||||
} |
||||
} |
||||
|
||||
// Store the final list of types in the fungusBindings object |
||||
SerializedProperty boundTypesProp = serializedObject.FindProperty("boundTypes"); |
||||
boundTypesProp.ClearArray(); |
||||
int index = 0; |
||||
foreach (System.Type t in typeSet) |
||||
{ |
||||
boundTypesProp.InsertArrayElementAtIndex(index); |
||||
SerializedProperty element = boundTypesProp.GetArrayElementAtIndex(index); |
||||
element.stringValue = t.AssemblyQualifiedName; |
||||
index++; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Adds the type to the set of types, and then uses reflection to add |
||||
/// all public fields, properties and methods to the set of types. |
||||
/// </summary> |
||||
protected virtual void AddAllSubTypes(HashSet<System.Type> typeSet, System.Type t) |
||||
{ |
||||
AddSubType(typeSet, t); |
||||
|
||||
MemberInfo[] memberInfos = t.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); |
||||
foreach (MemberInfo memberInfo in memberInfos) |
||||
{ |
||||
if (memberInfo.MemberType == MemberTypes.Field) |
||||
{ |
||||
FieldInfo fieldInfo = memberInfo as FieldInfo; |
||||
AddSubType(typeSet, fieldInfo.FieldType); |
||||
} |
||||
else if (memberInfo.MemberType == MemberTypes.Property) |
||||
{ |
||||
PropertyInfo propertyInfo = memberInfo as PropertyInfo; |
||||
AddSubType(typeSet, propertyInfo.PropertyType); |
||||
} |
||||
else if (memberInfo.MemberType == MemberTypes.Method) |
||||
{ |
||||
MethodInfo methodInfo = memberInfo as MethodInfo; |
||||
if (methodInfo.IsGenericMethod) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
if (methodInfo.ReturnType != typeof(void)) |
||||
{ |
||||
AddSubType(typeSet, methodInfo.ReturnType); |
||||
} |
||||
|
||||
foreach (ParameterInfo pi in methodInfo.GetParameters() ) |
||||
{ |
||||
AddSubType(typeSet, pi.ParameterType); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Adds a single type to the type set. |
||||
/// IEnumerable and IEnumerator types are handled specially. |
||||
/// </summary> |
||||
protected virtual void AddSubType(HashSet<System.Type> typeSet, System.Type t) |
||||
{ |
||||
// MoonSharp handles IEnumerator and IEnumerable types automatically, so just |
||||
// register the generic type used. |
||||
if (typeof(IEnumerable).IsAssignableFrom(t) || |
||||
typeof(IEnumerator).IsAssignableFrom(t)) |
||||
{ |
||||
System.Type[] genericArguments = t.GetGenericArguments(); |
||||
if (genericArguments.Count() == 1) |
||||
{ |
||||
System.Type containedType = genericArguments[0]; |
||||
|
||||
// The generic type could itself be an IEnumerator or IEnumerable, so |
||||
// recursively check for this case. |
||||
AddSubType(typeSet, containedType); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// Non-IEnumerable/IEnumerator types will be registered. |
||||
typeSet.Add(t); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 1b3ef64b6145248f6b3d106f09bace3a |
||||
timeCreated: 1455050970 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,197 @@
|
||||
// Adapted from the Unity Test Tools project (MIT license) |
||||
// https://bitbucket.org/Unity-Technologies/unitytesttools/src/a30d562427e9/Assets/UnityTestTools/ |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Reflection; |
||||
using UnityEditor; |
||||
using UnityEngine; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
[CustomEditor(typeof(FungusInvoke))] |
||||
public class FungusInvokeEditor : Editor |
||||
{ |
||||
private readonly DropDownControl<Type> m_ComparerDropDown = new DropDownControl<Type>(); |
||||
|
||||
#region GUI Contents |
||||
private readonly GUIContent m_GUIExecuteAfterTimeGuiContent = new GUIContent("Execute after (seconds)", "After how many seconds the script should be executed"); |
||||
private readonly GUIContent m_GUIRepeatExecuteTimeGuiContent = new GUIContent("Repeat execute", "Should the execution be repeated."); |
||||
private readonly GUIContent m_GUIRepeatEveryTimeGuiContent = new GUIContent("Frequency of repetitions", "How often should the execution be done"); |
||||
private readonly GUIContent m_GUIExecuteAfterFramesGuiContent = new GUIContent("Execute after (frames)", "After how many frames the script should be executed"); |
||||
private readonly GUIContent m_GUIRepeatExecuteFrameGuiContent = new GUIContent("Repeat execution", "Should the execution be repeated."); |
||||
#endregion |
||||
|
||||
protected SerializedProperty fungusScriptProp; |
||||
protected SerializedProperty runAsCoroutineProp; |
||||
protected SerializedProperty luaFileProp; |
||||
protected SerializedProperty luaScriptProp; |
||||
protected SerializedProperty useFungusModuleProp; |
||||
|
||||
protected List<TextAsset> luaFiles = new List<TextAsset>(); |
||||
|
||||
public FungusInvokeEditor() |
||||
{ |
||||
m_ComparerDropDown.convertForButtonLabel = type => type.Name; |
||||
m_ComparerDropDown.convertForGUIContent = type => type.Name; |
||||
m_ComparerDropDown.ignoreConvertForGUIContent = types => false; |
||||
m_ComparerDropDown.tooltip = "Comparer that will be used to compare values and determine the result of assertion."; |
||||
} |
||||
|
||||
public virtual void OnEnable() |
||||
{ |
||||
fungusScriptProp = serializedObject.FindProperty("fungusScript"); |
||||
runAsCoroutineProp = serializedObject.FindProperty("runAsCoroutine"); |
||||
luaFileProp = serializedObject.FindProperty("luaFile"); |
||||
luaScriptProp = serializedObject.FindProperty("luaScript"); |
||||
useFungusModuleProp = serializedObject.FindProperty("useFungusModule"); |
||||
|
||||
// Make a note of all Lua files in the project resources |
||||
object[] result = Resources.LoadAll("Lua", typeof(TextAsset)); |
||||
luaFiles.Clear(); |
||||
foreach (object res in result) |
||||
{ |
||||
TextAsset ta = res as TextAsset; |
||||
|
||||
// Ignore the built-in modules as you'll never want to execute these |
||||
if (ta == null || |
||||
ta.name == "fungus" || |
||||
ta.name == "inspect") |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
luaFiles.Add(ta); |
||||
} |
||||
} |
||||
|
||||
public override void OnInspectorGUI() |
||||
{ |
||||
var fungusInvoke = (FungusInvoke)target; |
||||
EditorGUILayout.BeginHorizontal(); |
||||
EditorGUILayout.PrefixLabel(new GUIContent("On Event")); |
||||
fungusInvoke.executeMethods = (FungusInvoke.ExecuteMethod)EditorGUILayout.EnumMaskField(fungusInvoke.executeMethods, |
||||
EditorStyles.popup, |
||||
GUILayout.ExpandWidth(false)); |
||||
EditorGUILayout.EndHorizontal(); |
||||
|
||||
if (fungusInvoke.IsExecuteMethodSelected(FungusInvoke.ExecuteMethod.AfterPeriodOfTime)) |
||||
{ |
||||
DrawOptionsForAfterPeriodOfTime(fungusInvoke); |
||||
} |
||||
|
||||
if (fungusInvoke.IsExecuteMethodSelected(FungusInvoke.ExecuteMethod.Update)) |
||||
{ |
||||
DrawOptionsForOnUpdate(fungusInvoke); |
||||
} |
||||
|
||||
if (Application.isPlaying) |
||||
{ |
||||
EditorGUILayout.BeginHorizontal(); |
||||
GUILayout.FlexibleSpace(); |
||||
|
||||
if (GUILayout.Button(new GUIContent("Execute Now", "Execute the Lua script immediately."))) |
||||
{ |
||||
fungusInvoke.Execute(); |
||||
} |
||||
|
||||
GUILayout.FlexibleSpace(); |
||||
EditorGUILayout.EndHorizontal(); |
||||
} |
||||
|
||||
serializedObject.Update(); |
||||
|
||||
EditorGUILayout.PropertyField(fungusScriptProp); |
||||
EditorGUILayout.PropertyField(runAsCoroutineProp); |
||||
EditorGUILayout.PropertyField(useFungusModuleProp); |
||||
|
||||
int selected = 0; |
||||
List<GUIContent> options = new List<GUIContent>(); |
||||
options.Add(new GUIContent("<Lua Script>")); |
||||
int index = 1; |
||||
if (luaFiles != null) |
||||
{ |
||||
foreach (TextAsset textAsset in luaFiles) |
||||
{ |
||||
options.Add(new GUIContent(textAsset.name)); |
||||
|
||||
if (luaFileProp.objectReferenceValue == textAsset) |
||||
{ |
||||
selected = index; |
||||
} |
||||
|
||||
index++; |
||||
} |
||||
} |
||||
|
||||
selected = EditorGUILayout.Popup(new GUIContent("Execute Lua", "Lua file or script to execute."), selected, options.ToArray()); |
||||
if (selected == 0) |
||||
{ |
||||
luaFileProp.objectReferenceValue = null; |
||||
} |
||||
else |
||||
{ |
||||
luaFileProp.objectReferenceValue = luaFiles[selected - 1]; |
||||
} |
||||
|
||||
if (luaFileProp.objectReferenceValue == null) |
||||
{ |
||||
EditorGUILayout.PropertyField(luaScriptProp); |
||||
} |
||||
else |
||||
{ |
||||
EditorGUILayout.BeginHorizontal(); |
||||
GUILayout.FlexibleSpace(); |
||||
|
||||
if (GUILayout.Button(new GUIContent("Open in Editor", "Open this Lua file in the external text editor."))) |
||||
{ |
||||
string path = AssetDatabase.GetAssetPath(luaFileProp.objectReferenceValue); |
||||
UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(path, 0); |
||||
} |
||||
|
||||
GUILayout.FlexibleSpace(); |
||||
EditorGUILayout.EndHorizontal(); |
||||
} |
||||
|
||||
serializedObject.ApplyModifiedProperties(); |
||||
} |
||||
|
||||
private void DrawOptionsForAfterPeriodOfTime(FungusInvoke script) |
||||
{ |
||||
EditorGUILayout.Space(); |
||||
script.executeAfterTime = EditorGUILayout.FloatField(m_GUIExecuteAfterTimeGuiContent, |
||||
script.executeAfterTime); |
||||
if (script.executeAfterTime < 0) |
||||
script.executeAfterTime = 0; |
||||
script.repeatExecuteTime = EditorGUILayout.Toggle(m_GUIRepeatExecuteTimeGuiContent, |
||||
script.repeatExecuteTime); |
||||
if (script.repeatExecuteTime) |
||||
{ |
||||
script.repeatEveryTime = EditorGUILayout.FloatField(m_GUIRepeatEveryTimeGuiContent, |
||||
script.repeatEveryTime); |
||||
if (script.repeatEveryTime < 0) |
||||
script.repeatEveryTime = 0; |
||||
} |
||||
} |
||||
|
||||
private void DrawOptionsForOnUpdate(FungusInvoke script) |
||||
{ |
||||
EditorGUILayout.Space(); |
||||
script.executeAfterFrames = EditorGUILayout.IntField(m_GUIExecuteAfterFramesGuiContent, |
||||
script.executeAfterFrames); |
||||
if (script.executeAfterFrames < 1) |
||||
script.executeAfterFrames = 1; |
||||
script.repeatExecuteFrame = EditorGUILayout.Toggle(m_GUIRepeatExecuteFrameGuiContent, |
||||
script.repeatExecuteFrame); |
||||
if (script.repeatExecuteFrame) |
||||
{ |
||||
script.repeatEveryFrame = EditorGUILayout.IntField(m_GUIRepeatEveryTimeGuiContent, |
||||
script.repeatEveryFrame); |
||||
if (script.repeatEveryFrame < 1) |
||||
script.repeatEveryFrame = 1; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 28e6892c983f34f42a3d6d03b5d199e7 |
||||
timeCreated: 1455233798 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,89 @@
|
||||
using UnityEngine; |
||||
using UnityEditor; |
||||
using System.IO; |
||||
using System.Collections; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
public class MenuItems |
||||
{ |
||||
[MenuItem("Tools/Fungus/Create/Fungus Script", false, 2000)] |
||||
static void CreateFungusScript() |
||||
{ |
||||
SpawnPrefab("Prefabs/FungusScript", false); |
||||
} |
||||
|
||||
[MenuItem("Tools/Fungus/Create/Fungus Bindings", false, 2001)] |
||||
static void CreateFungusBindings() |
||||
{ |
||||
SpawnPrefab("Prefabs/FungusBindings", false); |
||||
} |
||||
|
||||
[MenuItem("Tools/Fungus/Create/Fungus Invoke", false, 2002)] |
||||
static void CreateFungusInvoke() |
||||
{ |
||||
SpawnPrefab("Prefabs/FungusInvoke", false); |
||||
} |
||||
|
||||
[MenuItem("Tools/Fungus/Create/Lua File", false, 2100)] |
||||
static void CreateLuaFile() |
||||
{ |
||||
string path = EditorUtility.SaveFilePanelInProject("Create Lua File", "script.txt", "txt", "Please select a file name for the new Lua script. Note: Lua files in Unity use the .txt extension."); |
||||
if(path.Length == 0) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
File.WriteAllText(path, ""); |
||||
AssetDatabase.Refresh(); |
||||
|
||||
Object asset = AssetDatabase.LoadAssetAtPath<Object>(path); |
||||
if (asset != null) |
||||
{ |
||||
EditorUtility.FocusProjectWindow(); |
||||
EditorGUIUtility.PingObject(asset); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Spawns a prefab in the scene based on it's filename in a Resources folder in the project. |
||||
/// If centerInScene is true then the object will be placed centered in the view window with z = 0. |
||||
/// If centerInScene is false the the object will be placed at (0,0,0) |
||||
/// </summary> |
||||
public static GameObject SpawnPrefab(string prefabName, bool centerInScene) |
||||
{ |
||||
GameObject prefab = Resources.Load<GameObject>(prefabName); |
||||
if (prefab == null) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
GameObject go = PrefabUtility.InstantiatePrefab(prefab) as GameObject; |
||||
PrefabUtility.DisconnectPrefabInstance(go); |
||||
|
||||
if (centerInScene) |
||||
{ |
||||
SceneView view = SceneView.lastActiveSceneView; |
||||
if (view != null) |
||||
{ |
||||
Camera sceneCam = view.camera; |
||||
Vector3 pos = sceneCam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 10f)); |
||||
pos.z = 0f; |
||||
go.transform.position = pos; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
go.transform.position = Vector3.zero; |
||||
} |
||||
|
||||
Selection.activeGameObject = go; |
||||
|
||||
Undo.RegisterCreatedObjectUndo(go, "Create Object"); |
||||
|
||||
return go; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 88272117b50644b24a3f22cadef823ae |
||||
timeCreated: 1455875727 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,153 @@
|
||||
using UnityEngine; |
||||
using System; |
||||
using System.Reflection; |
||||
using System.Linq; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using MoonSharp.Interpreter; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
/// <summary> |
||||
/// Component which manages a list of bound objects to be accessed in Lua scripts. |
||||
/// </summary> |
||||
[ExecuteInEditMode] |
||||
public class FungusBindings : MonoBehaviour |
||||
{ |
||||
/// <summary> |
||||
/// Represents a single Unity object (+ optional component) bound to a string key. |
||||
/// </summary> |
||||
[Serializable] |
||||
public class BoundObject |
||||
{ |
||||
public string key; |
||||
public UnityEngine.Object obj; |
||||
public Component component; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Name of global table variable to store bindings in. If left blank then each binding will be added as a global variable. |
||||
/// </summary> |
||||
[Tooltip("Name of global table variable to store bindings in. If left blank then each binding will be added as a global variable.")] |
||||
public string tableName = ""; |
||||
|
||||
/// <summary> |
||||
/// The list of Unity objects to be bound for access in Lua. |
||||
/// </summary> |
||||
[Tooltip("The list of Unity objects to be bound to make them accessible in Lua script.")] |
||||
public List<BoundObject> boundObjects = new List<BoundObject>(); |
||||
|
||||
/// <summary> |
||||
/// The complete list of types used by the currently bound objects. |
||||
/// This includes the bound object types themselves, plus all the other types they use in public properties, fields and methods. |
||||
/// </summary> |
||||
[HideInInspector] |
||||
public List<string> boundTypes = new List<string>(); |
||||
|
||||
/// <summary> |
||||
/// Always ensure there is at least one row in the bound objects list. |
||||
/// </summary> |
||||
protected virtual void Update() |
||||
{ |
||||
// Add in a single empty line at start |
||||
if (boundObjects.Count == 0) |
||||
{ |
||||
boundObjects.Add(null); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Add all declared bindings to the globals table. |
||||
/// </summary> |
||||
public virtual void AddBindings(Table globals) |
||||
{ |
||||
Table bindingsTable = null; |
||||
if (tableName == "") |
||||
{ |
||||
// Add directly to globals table |
||||
bindingsTable = globals; |
||||
} |
||||
else |
||||
{ |
||||
DynValue res = globals.Get(tableName); |
||||
if (res.Type == DataType.Table) |
||||
{ |
||||
// Add to an existing table |
||||
bindingsTable = res.Table; |
||||
} |
||||
else |
||||
{ |
||||
// Create a new table |
||||
bindingsTable = new Table(globals.OwnerScript); |
||||
globals[tableName] = bindingsTable; |
||||
} |
||||
} |
||||
|
||||
if (bindingsTable == null) |
||||
{ |
||||
Debug.LogError("Bindings table must not be null"); |
||||
} |
||||
|
||||
RegisterBoundTypes(); |
||||
|
||||
for (int i = 0; i < boundObjects.Count; ++i) |
||||
{ |
||||
// Ignore empty keys |
||||
string key = boundObjects[i].key; |
||||
if (key == null || |
||||
key == "") |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Check for keys used multiple times |
||||
if (bindingsTable.Get(key).Type != DataType.Nil) |
||||
{ |
||||
Debug.LogWarning("An item already exists with the same key as binding '" + key + "'. This binding will be ignored."); |
||||
continue; |
||||
} |
||||
|
||||
// Ignore bindings with no object set |
||||
GameObject go = boundObjects[i].obj as GameObject; |
||||
if (go != null) |
||||
{ |
||||
// Register as gameobject / components |
||||
Component component = boundObjects[i].component; |
||||
if (component == null) |
||||
{ |
||||
// Bind the key to the gameobject |
||||
bindingsTable[key] = go; |
||||
} |
||||
else |
||||
{ |
||||
// Bind the key to the component |
||||
bindingsTable[key] = component; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// Register as other UnityEngine.Object type |
||||
bindingsTable[key] = boundObjects[i].obj; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Registers the list of bound types with MoonSharp. |
||||
/// </summary> |
||||
protected virtual void RegisterBoundTypes() |
||||
{ |
||||
foreach (string typeName in boundTypes) |
||||
{ |
||||
System.Type t = System.Type.GetType(typeName); |
||||
if (t != null && |
||||
!UserData.IsTypeRegistered(t)) |
||||
{ |
||||
UserData.RegisterType(t); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 4cc8a659e950044b69d7c62696c36962 |
||||
timeCreated: 1455049978 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,359 @@
|
||||
// Adapted from the Unity Test Tools project (MIT license) |
||||
// https://bitbucket.org/Unity-Technologies/unitytesttools/src/a30d562427e9/Assets/UnityTestTools/ |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using UnityEngine; |
||||
using Debug = UnityEngine.Debug; |
||||
using Object = UnityEngine.Object; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
[Serializable] |
||||
public class FungusInvoke : MonoBehaviour, IFungusInvokeConfigurator |
||||
{ |
||||
[Flags] |
||||
public enum ExecuteMethod |
||||
{ |
||||
AfterPeriodOfTime = 1 << 0, |
||||
Start = 1 << 1, |
||||
Update = 1 << 2, |
||||
FixedUpdate = 1 << 3, |
||||
LateUpdate = 1 << 4, |
||||
OnDestroy = 1 << 5, |
||||
OnEnable = 1 << 6, |
||||
OnDisable = 1 << 7, |
||||
OnControllerColliderHit = 1 << 8, |
||||
OnParticleCollision = 1 << 9, |
||||
OnJointBreak = 1 << 10, |
||||
OnBecameInvisible = 1 << 11, |
||||
OnBecameVisible = 1 << 12, |
||||
OnTriggerEnter = 1 << 13, |
||||
OnTriggerExit = 1 << 14, |
||||
OnTriggerStay = 1 << 15, |
||||
OnCollisionEnter = 1 << 16, |
||||
OnCollisionExit = 1 << 17, |
||||
OnCollisionStay = 1 << 18, |
||||
OnTriggerEnter2D = 1 << 19, |
||||
OnTriggerExit2D = 1 << 20, |
||||
OnTriggerStay2D = 1 << 21, |
||||
OnCollisionEnter2D = 1 << 22, |
||||
OnCollisionExit2D = 1 << 23, |
||||
OnCollisionStay2D = 1 << 24, |
||||
} |
||||
|
||||
[SerializeField] public float executeAfterTime = 1f; |
||||
[SerializeField] public bool repeatExecuteTime = true; |
||||
[SerializeField] public float repeatEveryTime = 1f; |
||||
[SerializeField] public int executeAfterFrames = 1; |
||||
[SerializeField] public bool repeatExecuteFrame = true; |
||||
[SerializeField] public int repeatEveryFrame = 1; |
||||
[SerializeField] public bool hasFailed; |
||||
|
||||
[SerializeField] public ExecuteMethod executeMethods = ExecuteMethod.Start; |
||||
|
||||
/// <summary> |
||||
/// The Lua script environment to use when executing. |
||||
/// </summary> |
||||
[Tooltip("The Lua script environment to use when executing.")] |
||||
public FungusScript fungusScript; |
||||
|
||||
/// <summary> |
||||
/// Lua script file to execute. |
||||
/// </summary> |
||||
[Tooltip("Lua script file to execute.")] |
||||
public TextAsset luaFile; |
||||
|
||||
/// <summary> |
||||
/// Lua script to execute. |
||||
/// </summary> |
||||
[Tooltip("Lua script to execute.")] |
||||
[TextArea(5, 50)] |
||||
public string luaScript = ""; |
||||
|
||||
/// <summary> |
||||
/// Run the script as a Lua coroutine so execution can be yielded for asynchronous operations. |
||||
/// </summary> |
||||
[Tooltip("Run the script as a Lua coroutine so execution can be yielded for asynchronous operations.")] |
||||
public bool runAsCoroutine = true; |
||||
|
||||
/// <summary> |
||||
/// Require the fungus Lua module at the start of the script. Equivalent to 'local fungus = require('fungus') |
||||
/// </summary> |
||||
[Tooltip("Require the fungus Lua module at the start of the script. Equivalent to 'local fungus = require('fungus')")] |
||||
public bool useFungusModule = true; |
||||
|
||||
private int m_ExecuteOnFrame; |
||||
|
||||
protected string friendlyName = ""; |
||||
|
||||
// Recursively build the full hierarchy path to this game object |
||||
private static string GetPath(Transform current) |
||||
{ |
||||
if (current.parent == null) |
||||
{ |
||||
return current.name; |
||||
} |
||||
return GetPath(current.parent) + "." + current.name; |
||||
} |
||||
|
||||
public void Start() |
||||
{ |
||||
// If no FungusScript has been explicitly set then try to get one in the scene |
||||
if (fungusScript == null) |
||||
{ |
||||
fungusScript = GetComponentInParent<FungusScript>(); |
||||
} |
||||
if (fungusScript == null) |
||||
{ |
||||
fungusScript = GameObject.FindObjectOfType<FungusScript>(); |
||||
} |
||||
|
||||
// Cache a descriptive name to use in Lua error messages |
||||
friendlyName = GetPath(transform) + ".FungusInvoke"; |
||||
|
||||
Execute(ExecuteMethod.Start); |
||||
|
||||
if (IsExecuteMethodSelected(ExecuteMethod.AfterPeriodOfTime)) |
||||
{ |
||||
StartCoroutine(ExecutePeriodically()); |
||||
} |
||||
if (IsExecuteMethodSelected(ExecuteMethod.Update)) |
||||
{ |
||||
m_ExecuteOnFrame = Time.frameCount + executeAfterFrames; |
||||
} |
||||
} |
||||
|
||||
public IEnumerator ExecutePeriodically() |
||||
{ |
||||
yield return new WaitForSeconds(executeAfterTime); |
||||
Execute(ExecuteMethod.AfterPeriodOfTime); |
||||
while (repeatExecuteTime) |
||||
{ |
||||
yield return new WaitForSeconds(repeatEveryTime); |
||||
Execute(ExecuteMethod.AfterPeriodOfTime); |
||||
} |
||||
} |
||||
|
||||
public bool ShouldExecuteOnFrame() |
||||
{ |
||||
if (Time.frameCount > m_ExecuteOnFrame) |
||||
{ |
||||
if (repeatExecuteFrame) |
||||
m_ExecuteOnFrame += repeatEveryFrame; |
||||
else |
||||
m_ExecuteOnFrame = Int32.MaxValue; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public void OnDisable() |
||||
{ |
||||
Execute(ExecuteMethod.OnDisable); |
||||
} |
||||
|
||||
public void OnEnable() |
||||
{ |
||||
Execute(ExecuteMethod.OnEnable); |
||||
} |
||||
|
||||
public void OnDestroy() |
||||
{ |
||||
Execute(ExecuteMethod.OnDestroy); |
||||
} |
||||
|
||||
public void Update() |
||||
{ |
||||
if (IsExecuteMethodSelected(ExecuteMethod.Update) && ShouldExecuteOnFrame()) |
||||
{ |
||||
Execute(ExecuteMethod.Update); |
||||
} |
||||
} |
||||
|
||||
public void FixedUpdate() |
||||
{ |
||||
Execute(ExecuteMethod.FixedUpdate); |
||||
} |
||||
|
||||
public void LateUpdate() |
||||
{ |
||||
Execute(ExecuteMethod.LateUpdate); |
||||
} |
||||
|
||||
public void OnControllerColliderHit() |
||||
{ |
||||
Execute(ExecuteMethod.OnControllerColliderHit); |
||||
} |
||||
|
||||
public void OnParticleCollision() |
||||
{ |
||||
Execute(ExecuteMethod.OnParticleCollision); |
||||
} |
||||
|
||||
public void OnJointBreak() |
||||
{ |
||||
Execute(ExecuteMethod.OnJointBreak); |
||||
} |
||||
|
||||
public void OnBecameInvisible() |
||||
{ |
||||
Execute(ExecuteMethod.OnBecameInvisible); |
||||
} |
||||
|
||||
public void OnBecameVisible() |
||||
{ |
||||
Execute(ExecuteMethod.OnBecameVisible); |
||||
} |
||||
|
||||
public void OnTriggerEnter() |
||||
{ |
||||
Execute(ExecuteMethod.OnTriggerEnter); |
||||
} |
||||
|
||||
public void OnTriggerExit() |
||||
{ |
||||
Execute(ExecuteMethod.OnTriggerExit); |
||||
} |
||||
|
||||
public void OnTriggerStay() |
||||
{ |
||||
Execute(ExecuteMethod.OnTriggerStay); |
||||
} |
||||
|
||||
public void OnCollisionEnter() |
||||
{ |
||||
Execute(ExecuteMethod.OnCollisionEnter); |
||||
} |
||||
|
||||
public void OnCollisionExit() |
||||
{ |
||||
Execute(ExecuteMethod.OnCollisionExit); |
||||
} |
||||
|
||||
public void OnCollisionStay() |
||||
{ |
||||
Execute(ExecuteMethod.OnCollisionStay); |
||||
} |
||||
|
||||
public void OnTriggerEnter2D() |
||||
{ |
||||
Execute(ExecuteMethod.OnTriggerEnter2D); |
||||
} |
||||
|
||||
public void OnTriggerExit2D() |
||||
{ |
||||
Execute(ExecuteMethod.OnTriggerExit2D); |
||||
} |
||||
|
||||
public void OnTriggerStay2D() |
||||
{ |
||||
Execute(ExecuteMethod.OnTriggerStay2D); |
||||
} |
||||
|
||||
public void OnCollisionEnter2D() |
||||
{ |
||||
Execute(ExecuteMethod.OnCollisionEnter2D); |
||||
} |
||||
|
||||
public void OnCollisionExit2D() |
||||
{ |
||||
Execute(ExecuteMethod.OnCollisionExit2D); |
||||
} |
||||
|
||||
public void OnCollisionStay2D() |
||||
{ |
||||
Execute(ExecuteMethod.OnCollisionStay2D); |
||||
} |
||||
|
||||
private void Execute(ExecuteMethod executeMethod) |
||||
{ |
||||
if (IsExecuteMethodSelected(executeMethod)) |
||||
{ |
||||
Execute(); |
||||
} |
||||
} |
||||
|
||||
public bool IsExecuteMethodSelected(ExecuteMethod method) |
||||
{ |
||||
return method == (executeMethods & method); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Execute the Lua script immediately. |
||||
/// This is the function to call if you want to trigger execution from an external script. |
||||
/// </summary> |
||||
public virtual void Execute() |
||||
{ |
||||
if (fungusScript == null) |
||||
{ |
||||
Debug.LogWarning("No FungusScript selected"); |
||||
} |
||||
else |
||||
{ |
||||
string s = ""; |
||||
if (useFungusModule) |
||||
{ |
||||
s = "fungus = require('fungus')\n"; |
||||
} |
||||
|
||||
if (luaFile != null) |
||||
{ |
||||
s += luaFile.text; |
||||
} |
||||
else if (luaScript.Length > 0) |
||||
{ |
||||
s += luaScript; |
||||
} |
||||
|
||||
fungusScript.DoLuaString(s, friendlyName, runAsCoroutine); |
||||
} |
||||
} |
||||
|
||||
#region AssertionComponentConfigurator |
||||
public int UpdateExecuteStartOnFrame { set { executeAfterFrames = value; } } |
||||
public int UpdateExecuteRepeatFrequency { set { repeatEveryFrame = value; } } |
||||
public bool UpdateExecuteRepeat { set { repeatExecuteFrame = value; } } |
||||
public float TimeExecuteStartAfter { set { executeAfterTime = value; } } |
||||
public float TimeExecuteRepeatFrequency { set { repeatEveryTime = value; } } |
||||
public bool TimeExecuteRepeat { set { repeatExecuteTime = value; } } |
||||
public FungusInvoke Component { get { return this; } } |
||||
#endregion |
||||
} |
||||
|
||||
public interface IFungusInvokeConfigurator |
||||
{ |
||||
/// <summary> |
||||
/// If the assertion is evaluated in Update, after how many frame should the evaluation start. Defult is 1 (first frame) |
||||
/// </summary> |
||||
int UpdateExecuteStartOnFrame { set; } |
||||
/// <summary> |
||||
/// If the assertion is evaluated in Update and UpdateExecuteRepeat is true, how many frame should pass between evaluations |
||||
/// </summary> |
||||
int UpdateExecuteRepeatFrequency { set; } |
||||
/// <summary> |
||||
/// If the assertion is evaluated in Update, should the evaluation be repeated after UpdateExecuteRepeatFrequency frames |
||||
/// </summary> |
||||
bool UpdateExecuteRepeat { set; } |
||||
|
||||
/// <summary> |
||||
/// If the assertion is evaluated after a period of time, after how many seconds the first evaluation should be done |
||||
/// </summary> |
||||
float TimeExecuteStartAfter { set; } |
||||
/// <summary> |
||||
/// If the assertion is evaluated after a period of time and TimeExecuteRepeat is true, after how many seconds should the next evaluation happen |
||||
/// </summary> |
||||
float TimeExecuteRepeatFrequency { set; } |
||||
/// <summary> |
||||
/// If the assertion is evaluated after a period, should the evaluation happen again after TimeExecuteRepeatFrequency seconds |
||||
/// </summary> |
||||
bool TimeExecuteRepeat { set; } |
||||
|
||||
FungusInvoke Component { get; } |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 446caeace65234baaacd52095d24f101 |
||||
timeCreated: 1455233789 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,110 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
/// <summary> |
||||
/// Wrapper class for PlayerPrefs that adds the concept of multiple save slots. |
||||
/// Save slots allow you to store multiple player save profiles. |
||||
/// </summary> |
||||
public class FungusPrefs |
||||
{ |
||||
/// <summary> |
||||
/// Deletes all saved values for all slots. |
||||
/// </summary> |
||||
public static void DeleteAll() |
||||
{ |
||||
PlayerPrefs.DeleteAll(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Removes key and its value from this save slot. |
||||
/// </summary> |
||||
public static void DeleteKey(int slot, string key) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
PlayerPrefs.DeleteKey(slotKey); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the float value associated with this key in this save slot, it it exists. |
||||
/// </summary> |
||||
public static float GetFloat(int slot, string key, float defaultValue = 0f) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
return PlayerPrefs.GetFloat(slotKey, defaultValue); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the int value associated with this key in this save slot, it it exists. |
||||
/// </summary> |
||||
public static int GetInt(int slot, string key, int defaultValue = 0) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
return PlayerPrefs.GetInt(slotKey, defaultValue); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the string value associated with this key in this save slot, it it exists. |
||||
/// </summary> |
||||
public static string GetString(int slot, string key, string defaultValue = "") |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
return PlayerPrefs.GetString(slotKey, defaultValue); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns true if the key exists in this save slot. |
||||
/// </summary> |
||||
public static bool HasKey(int slot, string key) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
return PlayerPrefs.HasKey(slotKey); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Writes all modified prefences to disk. |
||||
/// </summary> |
||||
public static void Save() |
||||
{ |
||||
PlayerPrefs.Save(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Sets the value of the preference identified by key for this save slot. |
||||
/// </summary> |
||||
public static void SetFloat(int slot, string key, float value) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
PlayerPrefs.SetFloat(slotKey, value); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Sets the value of the preference identified by key for this save slot. |
||||
/// </summary> |
||||
public static void SetInt(int slot, string key, int value) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
PlayerPrefs.SetInt(slotKey, value); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Sets the value of the preference identified by key for this save slot. |
||||
/// </summary> |
||||
public static void SetString(int slot, string key, string value) |
||||
{ |
||||
string slotKey = GetSlotKey(slot, key); |
||||
PlayerPrefs.SetString(slotKey, value); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the combined key used to identify a key within a save slot. |
||||
/// </summary> |
||||
private static string GetSlotKey(int slot, string key) |
||||
{ |
||||
return slot.ToString() + ":" + key; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: a9e5b64ab37dc4141963a6285c4000ee |
||||
timeCreated: 1455918227 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,527 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System; |
||||
using System.Linq; |
||||
using System.Diagnostics; |
||||
using System.Text.RegularExpressions; |
||||
using MoonSharp.Interpreter; |
||||
using MoonSharp.Interpreter.Interop; |
||||
using MoonSharp.Interpreter.Loaders; |
||||
using MoonSharp.RemoteDebugger; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
public class FungusScript : MonoBehaviour |
||||
{ |
||||
/// <summary> |
||||
/// Custom file loader for MoonSharp that loads in all Lua scripts in the project. |
||||
/// Scripts must be placed in a Resources/Lua directory. |
||||
/// </summary> |
||||
protected class FungusScriptLoader : ScriptLoaderBase |
||||
{ |
||||
// Give the script loader access to the list of accessible Lua Modules. |
||||
private IEnumerable<TextAsset> luaScripts; |
||||
public FungusScriptLoader(IEnumerable<TextAsset> luaScripts) |
||||
{ |
||||
this.luaScripts = luaScripts; |
||||
} |
||||
|
||||
/// <summary> |
||||
// Bypasses the standard path resolution logic for require. |
||||
/// </summary> |
||||
protected override string ResolveModuleName(string modname, string[] paths) |
||||
{ |
||||
return modname; |
||||
} |
||||
|
||||
public override object LoadFile(string file, Table globalContext) |
||||
{ |
||||
foreach (TextAsset luaScript in luaScripts) |
||||
{ |
||||
// Case insensitive string compare to allow standard Lua naming conventions in code |
||||
if (String.Compare(luaScript.name, file, true) == 0) |
||||
{ |
||||
return luaScript.text; |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
public override bool ScriptFileExists(string name) |
||||
{ |
||||
foreach (TextAsset luaScript in luaScripts) |
||||
{ |
||||
// Case insensitive string compare to allow standard Lua naming conventions in code |
||||
if (String.Compare(luaScript.name, name, true) == 0) |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
protected Script interpreter; |
||||
|
||||
/// <summary> |
||||
/// Returns the MoonSharp interpreter instance used to run Lua code. |
||||
/// </summary> |
||||
public Script Interpreter { get { return interpreter; } } |
||||
|
||||
/// <summary> |
||||
/// Launches the remote Lua debugger in your browser and breaks execution at the first executed Lua command. |
||||
/// </summary> |
||||
[Tooltip("Launches the remote Lua debugger in your browser and breaks execution at the first executed Lua command.")] |
||||
public bool remoteDebugger = false; |
||||
|
||||
/// <summary> |
||||
/// Lua script file which defines the global string table used for localisation. |
||||
/// </summary> |
||||
[Tooltip("Lua script file which defines the global string table used for localisation.")] |
||||
public TextAsset stringTable; |
||||
|
||||
/// <summary> |
||||
/// The currently selected language in the string table. Affects variable substitution. |
||||
/// </summary> |
||||
[Tooltip("The currently selected language in the string table. Affects variable substitution.")] |
||||
public string activeLanguage = "en"; |
||||
|
||||
/// <summary> |
||||
/// Time scale factor to apply when running Lua scripts. |
||||
/// This allows pausing of a FungusScript by setting timescale to 0. |
||||
/// Use the GetTime() and GetDeltaTime() functions to get scaled time values. |
||||
/// If negative, then GetTime() and GetDeltaTime() return the same values as the standard Time class. |
||||
/// </summary> |
||||
[Tooltip("Time scale factor to apply when running Lua scripts. If negative then uses the same values as the standard Time class.")] |
||||
public float timeScale = -1f; |
||||
|
||||
/// <summary> |
||||
/// Instance of remote debugging service when debugging option is enabled. |
||||
/// </summary> |
||||
protected RemoteDebuggerService remoteDebuggerService; |
||||
|
||||
/// <summary> |
||||
/// Flag used to avoid startup dependency issues. |
||||
/// </summary> |
||||
protected bool initialised = false; |
||||
|
||||
/// <summary> |
||||
/// Cached referenence to the string table (if loaded). |
||||
/// </summary> |
||||
protected Table stringTableCached; |
||||
|
||||
protected virtual void Start() |
||||
{ |
||||
InitInterpreter(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initialise the Lua interpreter so we can start running Lua code. |
||||
/// </summary> |
||||
public virtual void InitInterpreter() |
||||
{ |
||||
if (initialised) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
Script.DefaultOptions.DebugPrint = (s) => { UnityEngine.Debug.Log(s); }; |
||||
|
||||
// In some use cases (e.g. downloadable Lua files) some Lua modules can pose a potential security risk. |
||||
// You can restrict which core lua modules are available here if needed. |
||||
// See the MoonSharp documentation for details. |
||||
interpreter = new Script(CoreModules.Preset_Complete); |
||||
|
||||
RegisterLuaScriptFiles(); |
||||
RegisterCLRTypes(); |
||||
RegisterFungus(); |
||||
RegisterCLRClassObjects(); |
||||
RegisterBindings(); |
||||
LoadStringTable(); |
||||
|
||||
if (remoteDebugger) |
||||
{ |
||||
ActivateRemoteDebugger(interpreter); |
||||
} |
||||
|
||||
initialised = true; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Register all Lua files in the project so they can be accessed at runtime. |
||||
/// </summary> |
||||
protected virtual void RegisterLuaScriptFiles() |
||||
{ |
||||
object[] result = Resources.LoadAll("Lua", typeof(TextAsset)); |
||||
interpreter.Options.ScriptLoader = new FungusScriptLoader(result.OfType<TextAsset>()); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Registers a commonly used subset of Unity types for Lua interop. |
||||
/// To register more types externally to this class, register them in the Awake method of any |
||||
/// monobehavior in your scene. |
||||
/// </summary> |
||||
protected virtual void RegisterCLRTypes() |
||||
{ |
||||
// Core types needed by FungusScript |
||||
UserData.RegisterType<GameObject>(); |
||||
UserData.RegisterType<Component>(); |
||||
UserData.RegisterType<MonoBehaviour>(); |
||||
UserData.RegisterType<ScriptableObject>(); |
||||
UserData.RegisterType<IEnumerator>(); |
||||
UserData.RegisterType<UnityEngine.Coroutine>(); |
||||
UserData.RegisterType<Task>(); |
||||
|
||||
// Monobehaviors and other Unity.Objects |
||||
UserData.RegisterType<FungusScript>(); |
||||
UserData.RegisterType<Transform>(); |
||||
UserData.RegisterType<RectTransform>(); |
||||
UserData.RegisterType<Material>(); |
||||
UserData.RegisterType<Texture>(); |
||||
UserData.RegisterType<Sprite>(); |
||||
UserData.RegisterType<AudioClip>(); |
||||
UserData.RegisterType<AudioSource>(); |
||||
|
||||
// Value types |
||||
UserData.RegisterType<Vector2>(); |
||||
UserData.RegisterType<Vector3>(); |
||||
UserData.RegisterType<Rect>(); |
||||
UserData.RegisterType<Quaternion>(); |
||||
UserData.RegisterType<Color>(); |
||||
UserData.RegisterType<Time>(); |
||||
UserData.RegisterType<FungusPrefs>(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Registers the most common types used by Fungus. |
||||
/// </summary> |
||||
protected virtual void RegisterFungus() |
||||
{ |
||||
RegisterFungusTypes.Register(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Registers a commonly used subset of Unity class objects for Lua interop. |
||||
/// To register more class objects externally to this class, register them in the Awake method of any |
||||
/// monobehavior in your scene. |
||||
/// </summary> |
||||
protected virtual void RegisterCLRClassObjects() |
||||
{ |
||||
// Add the CLR class objects to a global unity table |
||||
Table unityTable = new Table(interpreter); |
||||
interpreter.Globals["unity"] = unityTable; |
||||
|
||||
// Instances of these types can be created in Lua using e.g. c = unity.color.__new() |
||||
unityTable["vector2"] = typeof(Vector2); |
||||
unityTable["vector3"] = typeof(Vector3); |
||||
unityTable["rect"] = typeof(Rect); |
||||
unityTable["quaternion"] = typeof(Quaternion); |
||||
unityTable["color"] = typeof(Color); |
||||
|
||||
// Static classes |
||||
unityTable["time"] = UserData.CreateStatic(typeof(Time)); |
||||
unityTable["fungusprefs"] = UserData.CreateStatic(typeof(FungusPrefs)); |
||||
|
||||
// This FungusScript object |
||||
unityTable["fungusscript"] = this; |
||||
|
||||
// Provide access to the Unity Test Tools (if available). |
||||
Type testType = Type.GetType("IntegrationTest"); |
||||
if (testType != null) |
||||
{ |
||||
UserData.RegisterType(testType); |
||||
unityTable["test"] = UserData.CreateStatic(testType); |
||||
} |
||||
|
||||
// Example of how to register an enum |
||||
// UserData.RegisterType<MyClass.MyEnum>(); |
||||
// interpreter.Globals.Set("MyEnum", UserData.CreateStatic<MyClass.MyEnum>()); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Binds all gameobjects and components defined in FungusBinding objects to the global scene table. |
||||
/// </summary> |
||||
protected virtual void RegisterBindings() |
||||
{ |
||||
FungusBindings[] bindings = GameObject.FindObjectsOfType<FungusBindings>(); |
||||
foreach (FungusBindings binding in bindings) |
||||
{ |
||||
binding.AddBindings(interpreter.Globals); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Loads the global string table used for localisation. |
||||
/// </summary> |
||||
protected virtual void LoadStringTable() |
||||
{ |
||||
if (stringTable != null) |
||||
{ |
||||
try |
||||
{ |
||||
DynValue stringTableRes = interpreter.DoString(stringTable.text); |
||||
if (stringTableRes.Type == DataType.Table) |
||||
{ |
||||
stringTableCached = stringTableRes.Table; |
||||
interpreter.Globals["stringtable"] = stringTableCached; |
||||
} |
||||
} |
||||
catch (ScriptRuntimeException ex) |
||||
{ |
||||
UnityEngine.Debug.LogError("Lua runtime error: " + ex.DecoratedMessage); |
||||
} |
||||
catch (InterpreterException ex) |
||||
{ |
||||
UnityEngine.Debug.LogError(ex.DecoratedMessage); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a string from the string table for this key. |
||||
/// The string returned depends on the active language. |
||||
/// </summary> |
||||
public virtual string GetString(string key) |
||||
{ |
||||
if (stringTableCached != null) |
||||
{ |
||||
// Match against string table and active language |
||||
DynValue stringTableVar = stringTableCached.Get(key); |
||||
if (stringTableVar.Type == DataType.Table) |
||||
{ |
||||
DynValue languageEntry = stringTableVar.Table.Get(activeLanguage); |
||||
if (languageEntry.Type == DataType.String) |
||||
{ |
||||
return languageEntry.String; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return ""; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Substitutes specially formatted tokens in the text with global variables and string table values. |
||||
/// The string table value used depends on the currently loaded string table and active language. |
||||
/// </summary> |
||||
public virtual string Substitute(string text) |
||||
{ |
||||
string subbedText = text; |
||||
|
||||
// Instantiate the regular expression object. |
||||
Regex r = new Regex("\\[\\$.*?\\]"); |
||||
|
||||
// Match the regular expression pattern against a text string. |
||||
var results = r.Matches(text); |
||||
foreach (Match match in results) |
||||
{ |
||||
string key = match.Value.Substring(2, match.Value.Length - 3); |
||||
|
||||
if (stringTableCached != null) |
||||
{ |
||||
// Match against string table and active language |
||||
DynValue stringTableVar = stringTableCached.Get(key); |
||||
if (stringTableVar.Type == DataType.Table) |
||||
{ |
||||
DynValue languageEntry = stringTableVar.Table.Get(activeLanguage); |
||||
if (languageEntry.Type == DataType.String) |
||||
{ |
||||
subbedText = subbedText.Replace(match.Value, languageEntry.String); |
||||
} |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
// Match against global variables |
||||
DynValue globalVar = interpreter.Globals.Get(key); |
||||
if (globalVar.Type != DataType.Nil) |
||||
{ |
||||
subbedText = subbedText.Replace(match.Value, globalVar.ToPrintString()); |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
return subbedText; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the time since level load, multiplied by timeScale. |
||||
/// If timeScale is negative then returns the same as Time.timeSinceLevelLoaded. |
||||
/// </summary> |
||||
public float GetTime() |
||||
{ |
||||
if (timeScale < 0f) |
||||
{ |
||||
return Time.timeSinceLevelLoad; |
||||
} |
||||
else |
||||
{ |
||||
return Time.unscaledTime * timeScale; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the delta time this frame, multiplied by timeScale. |
||||
/// If timeScale is negative then returns the same as Time.deltaTime. |
||||
/// </summary> |
||||
public float GetDeltaTime() |
||||
{ |
||||
if (timeScale < 0f) |
||||
{ |
||||
return Time.deltaTime; |
||||
} |
||||
else |
||||
{ |
||||
return Time.deltaTime * timeScale; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Load and run a string containing Lua script. May be run as a coroutine. |
||||
/// <param name="luaString">The Lua code to be run.</param> |
||||
/// <param name="friendlyName">A descriptive name to be used in error reports.</param> |
||||
/// <param name="runAsCoroutine">Run the Lua code as a coroutine to support asynchronous operations.</param> |
||||
/// <param name="onComplete">Method to callback when the Lua code finishes exection. Supports return parameters.</param> |
||||
/// </summary> |
||||
public void DoLuaString(string luaString, string friendlyName, bool runAsCoroutine, Action<DynValue> onComplete = null) |
||||
{ |
||||
InitInterpreter(); |
||||
|
||||
// Load the Lua script |
||||
DynValue res = null; |
||||
try |
||||
{ |
||||
res = interpreter.LoadString(luaString, null, friendlyName); |
||||
} |
||||
catch (InterpreterException ex) |
||||
{ |
||||
UnityEngine.Debug.LogError(ex.DecoratedMessage + "\n" + luaString); |
||||
} |
||||
|
||||
if (res == null) |
||||
{ |
||||
if (onComplete != null) |
||||
{ |
||||
onComplete(null); |
||||
} |
||||
|
||||
return; |
||||
} |
||||
|
||||
// Execute the Lua script |
||||
if (runAsCoroutine) |
||||
{ |
||||
StartCoroutine(RunLuaCoroutineInternal(res.Function, luaString, onComplete)); |
||||
} |
||||
else |
||||
{ |
||||
DynValue returnValue = null; |
||||
try |
||||
{ |
||||
returnValue = res.Function.Call(); |
||||
} |
||||
catch (InterpreterException ex) |
||||
{ |
||||
UnityEngine.Debug.LogError(ex.DecoratedMessage + "\n" + luaString); |
||||
} |
||||
|
||||
if (onComplete != null) |
||||
{ |
||||
onComplete(returnValue); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Starts a Unity coroutine which updates a Lua coroutine each frame. |
||||
/// <param name="closure">A MoonSharp closure object representing a function.</param> |
||||
/// <param name="debugInfo">Debug text to display if an exception occurs (usually the Lua code that is being executed).</param> |
||||
/// <param name="onComplete">A delegate method that is called when the coroutine completes. Includes return parameter.</param> |
||||
/// </summary> |
||||
public void RunLuaCoroutine(Closure closure, string debugInfo, Action<DynValue> onComplete = null) |
||||
{ |
||||
StartCoroutine(RunLuaCoroutineInternal(closure, debugInfo, onComplete)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// A Unity coroutine method which updates a Lua coroutine each frame. |
||||
/// <param name="closure">A MoonSharp closure object representing a function.</param> |
||||
/// <param name="debugInfo">Debug text to display if an exception occurs (usually the Lua code that is being executed).</param> |
||||
/// <param name="onComplete">A delegate method that is called when the coroutine completes. Includes return parameter.</param> |
||||
/// </summary> |
||||
protected IEnumerator RunLuaCoroutineInternal(Closure closure, string debugInfo, Action<DynValue> onComplete = null) |
||||
{ |
||||
DynValue co = interpreter.CreateCoroutine(closure); |
||||
|
||||
DynValue returnValue = null; |
||||
while (co.Coroutine.State != CoroutineState.Dead) |
||||
{ |
||||
try |
||||
{ |
||||
returnValue = co.Coroutine.Resume(); |
||||
} |
||||
catch (InterpreterException ex) |
||||
{ |
||||
UnityEngine.Debug.LogError(ex.DecoratedMessage + "\n" + debugInfo); |
||||
} |
||||
|
||||
yield return null; |
||||
} |
||||
|
||||
if (onComplete != null) |
||||
{ |
||||
onComplete(returnValue); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Start a Unity coroutine from a Lua call. |
||||
/// </summary> |
||||
public Task RunUnityCoroutine(IEnumerator coroutine) |
||||
{ |
||||
if (coroutine == null) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
// We use the Task class so we can poll the coroutine to check if it has finished. |
||||
// Standard Unity coroutines don't support this check. |
||||
return new Task(RunUnityCoroutineImpl(coroutine)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Starts a standard Unity coroutine. |
||||
/// The coroutine is managed by the FungusScript monobehavior, so you can call StopAllCoroutines to |
||||
/// stop all active coroutines later. |
||||
/// </summary> |
||||
protected virtual IEnumerator RunUnityCoroutineImpl(IEnumerator coroutine) |
||||
{ |
||||
if (coroutine == null) |
||||
{ |
||||
UnityEngine.Debug.LogWarning("Coroutine must not be null"); |
||||
yield break; |
||||
} |
||||
|
||||
yield return StartCoroutine(coroutine); |
||||
} |
||||
|
||||
protected virtual void ActivateRemoteDebugger(Script script) |
||||
{ |
||||
if (remoteDebuggerService == null) |
||||
{ |
||||
remoteDebuggerService = new RemoteDebuggerService(); |
||||
|
||||
// the last boolean is to specify if the script is free to run |
||||
// after attachment, defaults to false |
||||
remoteDebuggerService.Attach(script, gameObject.name, false); |
||||
} |
||||
|
||||
// start the web-browser at the correct url. Replace this or just |
||||
// pass the url to the user in some way. |
||||
Process.Start(remoteDebuggerService.HttpUrlStringLocalHost); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: ba19c26c1ba7243d2b57ebc4329cc7c6 |
||||
timeCreated: 1454343267 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: b370c105afb8a4e32bb641b7f6c6048c |
||||
folderAsset: yes |
||||
timeCreated: 1454683923 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: e8ec7018e2e8c474e8ae39737a286c0a |
||||
folderAsset: yes |
||||
timeCreated: 1456312519 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,155 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using Fungus; |
||||
using MoonSharp.Interpreter; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
[CommandInfo("FungusScript", |
||||
"Execute Lua", |
||||
"Executes a Lua code chunk using a FungusScript object.")] |
||||
public class ExecuteLua : Command |
||||
{ |
||||
[Tooltip("FungusScript to use to execute this Lua script")] |
||||
public FungusScript fungusScript; |
||||
|
||||
[TextArea(10,100)] |
||||
[Tooltip("Lua script to execute. Use {$VarName} to insert a Flowchart variable in the Lua script.")] |
||||
public string luaScript; |
||||
|
||||
/// <summary> |
||||
/// Require the fungus Lua module at the start of the script. Equivalent to 'local fungus = require('fungus') |
||||
/// </summary> |
||||
[Tooltip("Require the fungus Lua module at the start of the script. Equivalent to 'local fungus = require('fungus')")] |
||||
public bool useFungusModule = true; |
||||
|
||||
[Tooltip("Execute this Lua script as a Lua coroutine")] |
||||
public bool runAsCoroutine = true; |
||||
|
||||
[Tooltip("Pause command execution until the Lua script has finished execution")] |
||||
public bool waitUntilFinished = true; |
||||
|
||||
[Tooltip("A Flowchart variable to store the returned value in.")] |
||||
[VariableProperty()] |
||||
public Variable returnVariable; |
||||
|
||||
protected string friendlyName = ""; |
||||
|
||||
protected virtual void Start() |
||||
{ |
||||
// Cache a descriptive name to use in Lua error messages |
||||
friendlyName = gameObject.name + "." + parentBlock.blockName + "." + "ExecuteLua #" + commandIndex.ToString(); |
||||
} |
||||
|
||||
public override void OnEnter() |
||||
{ |
||||
if (fungusScript == null) |
||||
{ |
||||
Debug.LogWarning("No FungusScript object selected"); |
||||
Continue(); |
||||
return; |
||||
} |
||||
|
||||
string s = ""; |
||||
if (useFungusModule) |
||||
{ |
||||
s = "fungus = require('fungus')\n"; |
||||
} |
||||
|
||||
string subbed = s + GetFlowchart().SubstituteVariables(luaScript); |
||||
|
||||
fungusScript.DoLuaString(subbed, friendlyName, runAsCoroutine, (returnValue) => { |
||||
StoreReturnVariable(returnValue); |
||||
if (waitUntilFinished) |
||||
{ |
||||
Continue(); |
||||
} |
||||
}); |
||||
|
||||
if (!waitUntilFinished) |
||||
{ |
||||
Continue(); |
||||
} |
||||
} |
||||
|
||||
protected virtual void StoreReturnVariable(DynValue returnValue) |
||||
{ |
||||
if (returnVariable == null || returnValue == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
// Store the return value in a Fungus Variable |
||||
System.Type variableType = returnVariable.GetType(); |
||||
if (variableType == typeof(BooleanVariable) && returnValue.Type == DataType.Boolean) |
||||
{ |
||||
(returnVariable as BooleanVariable).value = returnValue.Boolean; |
||||
} |
||||
else if (variableType == typeof(IntegerVariable) && returnValue.Type == DataType.Number) |
||||
{ |
||||
(returnVariable as IntegerVariable).value = (int)returnValue.Number; |
||||
} |
||||
else if (variableType == typeof(FloatVariable) && returnValue.Type == DataType.Number) |
||||
{ |
||||
(returnVariable as FloatVariable).value = (float)returnValue.Number; |
||||
} |
||||
else if (variableType == typeof(StringVariable) && returnValue.Type == DataType.String) |
||||
{ |
||||
(returnVariable as StringVariable).value = returnValue.String; |
||||
} |
||||
else if (variableType == typeof(ColorVariable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as ColorVariable).value = returnValue.CheckUserDataType<Color>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(GameObjectVariable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as GameObjectVariable).value = returnValue.CheckUserDataType<GameObject>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(MaterialVariable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as MaterialVariable).value = returnValue.CheckUserDataType<Material>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(ObjectVariable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as ObjectVariable).value = returnValue.CheckUserDataType<Object>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(SpriteVariable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as SpriteVariable).value = returnValue.CheckUserDataType<Sprite>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(TextureVariable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as TextureVariable).value = returnValue.CheckUserDataType<Texture>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(Vector2Variable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as Vector2Variable).value = returnValue.CheckUserDataType<Vector2>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else if (variableType == typeof(Vector3Variable) && returnValue.Type == DataType.UserData) |
||||
{ |
||||
(returnVariable as Vector3Variable).value = returnValue.CheckUserDataType<Vector3>("ExecuteLua.StoreReturnVariable"); |
||||
} |
||||
else |
||||
{ |
||||
Debug.LogError("Failed to convert " + returnValue.Type.ToLuaTypeString() + " return type to " + variableType.ToString()); |
||||
} |
||||
} |
||||
|
||||
public override string GetSummary() |
||||
{ |
||||
if (fungusScript == null) |
||||
{ |
||||
return "Error: No FungusScript object selected"; |
||||
} |
||||
|
||||
return luaScript; |
||||
} |
||||
|
||||
public override Color GetButtonColor() |
||||
{ |
||||
return new Color32(235, 191, 217, 255); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 71f455683d4ba4405b8dbba457159620 |
||||
timeCreated: 1456398214 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,97 @@
|
||||
using UnityEngine; |
||||
using UnityEngine.UI; |
||||
using System.Collections; |
||||
using Fungus; |
||||
using MoonSharp.Interpreter; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
public static class FungusScriptExtensions |
||||
{ |
||||
|
||||
/// <summary> |
||||
/// Extension for MenuDialog that allows AddOption to call a Lua function when an option is selected. |
||||
/// </summary> |
||||
public static bool AddOption(this MenuDialog menuDialog, string text, bool interactable, FungusScript fungusScript, Closure callBack) |
||||
{ |
||||
bool addedOption = false; |
||||
foreach (Button button in menuDialog.cachedButtons) |
||||
{ |
||||
if (!button.gameObject.activeSelf) |
||||
{ |
||||
button.gameObject.SetActive(true); |
||||
|
||||
button.interactable = interactable; |
||||
|
||||
Text textComponent = button.GetComponentInChildren<Text>(); |
||||
if (textComponent != null) |
||||
{ |
||||
textComponent.text = text; |
||||
} |
||||
|
||||
button.onClick.AddListener(delegate { |
||||
|
||||
menuDialog.StopAllCoroutines(); // Stop timeout |
||||
menuDialog.Clear(); |
||||
|
||||
menuDialog.HideSayDialog(); |
||||
|
||||
menuDialog.gameObject.SetActive(false); |
||||
|
||||
if (callBack != null) |
||||
{ |
||||
fungusScript.RunLuaCoroutine(callBack, text); |
||||
} |
||||
}); |
||||
|
||||
addedOption = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return addedOption; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Extension for MenuDialog that allows ShowTimer to call a Lua function when the timer expires. |
||||
/// </summary> |
||||
public static IEnumerator ShowTimer(this MenuDialog menuDialog, float duration, FungusScript fungusScript, Closure callBack) |
||||
{ |
||||
if (menuDialog.cachedSlider == null || |
||||
duration <= 0f) |
||||
{ |
||||
yield break; |
||||
} |
||||
|
||||
menuDialog.cachedSlider.gameObject.SetActive(true); |
||||
menuDialog.StopAllCoroutines(); |
||||
|
||||
float elapsedTime = 0; |
||||
Slider timeoutSlider = menuDialog.GetComponentInChildren<Slider>(); |
||||
|
||||
while (elapsedTime < duration) |
||||
{ |
||||
if (timeoutSlider != null) |
||||
{ |
||||
float t = 1f - elapsedTime / duration; |
||||
timeoutSlider.value = t; |
||||
} |
||||
|
||||
elapsedTime += Time.deltaTime; |
||||
|
||||
yield return null; |
||||
} |
||||
|
||||
menuDialog.Clear(); |
||||
menuDialog.gameObject.SetActive(false); |
||||
menuDialog.HideSayDialog(); |
||||
|
||||
if (callBack != null) |
||||
{ |
||||
fungusScript.RunLuaCoroutine(callBack, "menutimer"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: d3cdbb71635f4406baec64f33d24514f |
||||
timeCreated: 1456230091 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,40 @@
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
using MoonSharp.Interpreter; |
||||
using Fungus; |
||||
|
||||
namespace Fungus |
||||
{ |
||||
|
||||
public class RegisterFungusTypes |
||||
{ |
||||
/// <summary> |
||||
/// Extension for FungusScript that registers all types used by Fungus. |
||||
/// </summary> |
||||
public static void Register() |
||||
{ |
||||
UserData.RegisterType<Flowchart>(); |
||||
UserData.RegisterType<Block>(); |
||||
UserData.RegisterType<Variable>(); |
||||
UserData.RegisterType<BooleanVariable>(); |
||||
UserData.RegisterType<ColorVariable>(); |
||||
UserData.RegisterType<FloatVariable>(); |
||||
UserData.RegisterType<GameObjectVariable>(); |
||||
UserData.RegisterType<IntegerVariable>(); |
||||
UserData.RegisterType<MaterialVariable>(); |
||||
UserData.RegisterType<ObjectVariable>(); |
||||
UserData.RegisterType<SpriteVariable>(); |
||||
UserData.RegisterType<StringVariable>(); |
||||
UserData.RegisterType<TextureVariable>(); |
||||
UserData.RegisterType<Vector2Variable>(); |
||||
UserData.RegisterType<Vector3Variable>(); |
||||
UserData.RegisterType<AnimatorVariable>(); |
||||
UserData.RegisterType<AudioSourceVariable>(); |
||||
UserData.RegisterType<TransformVariable>(); |
||||
|
||||
// Extension types |
||||
UserData.RegisterExtensionType(typeof(FungusScriptExtensions)); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: becdb52a4ba7c476d89008442adfc3ef |
||||
timeCreated: 1458920418 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 483efc3d00eeb41e99e9472ecf3c3bd4 |
||||
folderAsset: yes |
||||
timeCreated: 1454345352 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,36 @@
|
||||
Copyright (c) 2014, Marco Mastropaolo |
||||
All rights reserved. |
||||
|
||||
Parts of the string library are based on the KopiLua project (https://github.com/NLua/KopiLua) |
||||
Copyright (c) 2012 LoDC |
||||
|
||||
Debugger icons are from the Eclipse project (https://www.eclipse.org/). |
||||
Copyright of The Eclipse Foundation |
||||
|
||||
The MoonSharp icon is (c) Isaac, 2014-2015 |
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this |
||||
list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, |
||||
this list of conditions and the following disclaimer in the documentation |
||||
and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of the {organization} nor the names of its |
||||
contributors may be used to endorse or promote products derived from |
||||
this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 77bed9ffa87904128bf91eb0d73bd35e |
||||
timeCreated: 1455193522 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 39a7bcc4c4db443cc85a13a12555c9f7 |
||||
timeCreated: 1456222254 |
||||
licenseType: Free |
||||
PluginImporter: |
||||
serializedVersion: 1 |
||||
iconMap: {} |
||||
executionOrder: {} |
||||
isPreloaded: 0 |
||||
platformData: |
||||
Any: |
||||
enabled: 1 |
||||
settings: {} |
||||
Editor: |
||||
enabled: 0 |
||||
settings: |
||||
DefaultValueInitialized: true |
||||
WindowsStoreApps: |
||||
enabled: 0 |
||||
settings: |
||||
CPU: AnyCPU |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: af73bc91714a54f6a9e72ca6770987d8 |
||||
timeCreated: 1456222253 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 2d32648e4d82e4c3e837a7ad11352ac0 |
||||
timeCreated: 1454345354 |
||||
licenseType: Free |
||||
PluginImporter: |
||||
serializedVersion: 1 |
||||
iconMap: {} |
||||
executionOrder: {} |
||||
isPreloaded: 0 |
||||
platformData: |
||||
Any: |
||||
enabled: 1 |
||||
settings: {} |
||||
Editor: |
||||
enabled: 0 |
||||
settings: |
||||
DefaultValueInitialized: true |
||||
WindowsStoreApps: |
||||
enabled: 0 |
||||
settings: |
||||
CPU: AnyCPU |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 45b1b1eac93b04a4a8d6ec29d4803aa9 |
||||
timeCreated: 1454345352 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 894a26d5d6ca04417aef855d8dfefaf0 |
||||
timeCreated: 1454345354 |
||||
licenseType: Free |
||||
TextScriptImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
fileFormatVersion: 2 |
||||
guid: c3effdd4e9d074bcbb90e8773303ad3b |
||||
timeCreated: 1455193529 |
||||
licenseType: Free |
||||
PluginImporter: |
||||
serializedVersion: 1 |
||||
iconMap: {} |
||||
executionOrder: {} |
||||
isPreloaded: 0 |
||||
platformData: |
||||
Any: |
||||
enabled: 1 |
||||
settings: {} |
||||
Editor: |
||||
enabled: 0 |
||||
settings: |
||||
DefaultValueInitialized: true |
||||
WindowsStoreApps: |
||||
enabled: 0 |
||||
settings: |
||||
CPU: AnyCPU |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: f5996939cde6945dbaa205884e73d770 |
||||
timeCreated: 1455193522 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 4375c8dc0d3dd47a782783697a009e01 |
||||
timeCreated: 1456222253 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: bf214384dd01b4f59a0569536329c190 |
||||
folderAsset: yes |
||||
timeCreated: 1455049414 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,214 @@
|
||||
/// TaskManager.cs |
||||
/// Copyright (c) 2011, Ken Rockot <k-e-n-@-REMOVE-CAPS-AND-HYPHENS-oz.gs>. All rights reserved. |
||||
/// Everyone is granted non-exclusive license to do anything at all with this code. |
||||
/// |
||||
/// This is a new coroutine interface for Unity. |
||||
/// |
||||
/// The motivation for this is twofold: |
||||
/// |
||||
/// 1. The existing coroutine API provides no means of stopping specific |
||||
/// coroutines; StopCoroutine only takes a string argument, and it stops |
||||
/// all coroutines started with that same string; there is no way to stop |
||||
/// coroutines which were started directly from an enumerator. This is |
||||
/// not robust enough and is also probably pretty inefficient. |
||||
/// |
||||
/// 2. StartCoroutine and friends are MonoBehaviour methods. This means |
||||
/// that in order to start a coroutine, a user typically must have some |
||||
/// component reference handy. There are legitimate cases where such a |
||||
/// constraint is inconvenient. This implementation hides that |
||||
/// constraint from the user. |
||||
/// |
||||
/// Example usage: |
||||
/// |
||||
/// ---------------------------------------------------------------------------- |
||||
/// IEnumerator MyAwesomeTask() |
||||
/// { |
||||
/// while(true) { |
||||
/// Debug.Log("Logcat iz in ur consolez, spammin u wif messagez."); |
||||
/// yield return null; |
||||
//// } |
||||
/// } |
||||
/// |
||||
/// IEnumerator TaskKiller(float delay, Task t) |
||||
/// { |
||||
/// yield return new WaitForSeconds(delay); |
||||
/// t.Stop(); |
||||
/// } |
||||
/// |
||||
/// void SomeCodeThatCouldBeAnywhereInTheUniverse() |
||||
/// { |
||||
/// Task spam = new Task(MyAwesomeTask()); |
||||
/// new Task(TaskKiller(5, spam)); |
||||
/// } |
||||
/// ---------------------------------------------------------------------------- |
||||
/// |
||||
/// When SomeCodeThatCouldBeAnywhereInTheUniverse is called, the debug console |
||||
/// will be spammed with annoying messages for 5 seconds. |
||||
/// |
||||
/// Simple, really. There is no need to initialize or even refer to TaskManager. |
||||
/// When the first Task is created in an application, a "TaskManager" GameObject |
||||
/// will automatically be added to the scene root with the TaskManager component |
||||
/// attached. This component will be responsible for dispatching all coroutines |
||||
/// behind the scenes. |
||||
/// |
||||
/// Task also provides an event that is triggered when the coroutine exits. |
||||
|
||||
using UnityEngine; |
||||
using System.Collections; |
||||
|
||||
/// A Task object represents a coroutine. Tasks can be started, paused, and stopped. |
||||
/// It is an error to attempt to start a task that has been stopped or which has |
||||
/// naturally terminated. |
||||
public class Task |
||||
{ |
||||
/// Returns true if and only if the coroutine is running. Paused tasks |
||||
/// are considered to be running. |
||||
public bool Running { |
||||
get { |
||||
return task.Running; |
||||
} |
||||
} |
||||
|
||||
/// Returns true if and only if the coroutine is currently paused. |
||||
public bool Paused { |
||||
get { |
||||
return task.Paused; |
||||
} |
||||
} |
||||
|
||||
/// Delegate for termination subscribers. manual is true if and only if |
||||
/// the coroutine was stopped with an explicit call to Stop(). |
||||
public delegate void FinishedHandler(bool manual); |
||||
|
||||
/// Termination event. Triggered when the coroutine completes execution. |
||||
public event FinishedHandler Finished; |
||||
|
||||
/// Creates a new Task object for the given coroutine. |
||||
/// |
||||
/// If autoStart is true (default) the task is automatically started |
||||
/// upon construction. |
||||
public Task(IEnumerator c, bool autoStart = true) |
||||
{ |
||||
task = TaskManager.CreateTask(c); |
||||
task.Finished += TaskFinished; |
||||
if(autoStart) |
||||
Start(); |
||||
} |
||||
|
||||
/// Begins execution of the coroutine |
||||
public void Start() |
||||
{ |
||||
task.Start(); |
||||
} |
||||
|
||||
/// Discontinues execution of the coroutine at its next yield. |
||||
public void Stop() |
||||
{ |
||||
task.Stop(); |
||||
} |
||||
|
||||
public void Pause() |
||||
{ |
||||
task.Pause(); |
||||
} |
||||
|
||||
public void Unpause() |
||||
{ |
||||
task.Unpause(); |
||||
} |
||||
|
||||
void TaskFinished(bool manual) |
||||
{ |
||||
FinishedHandler handler = Finished; |
||||
if(handler != null) |
||||
handler(manual); |
||||
} |
||||
|
||||
TaskManager.TaskState task; |
||||
} |
||||
|
||||
class TaskManager : MonoBehaviour |
||||
{ |
||||
public class TaskState |
||||
{ |
||||
public bool Running { |
||||
get { |
||||
return running; |
||||
} |
||||
} |
||||
|
||||
public bool Paused { |
||||
get { |
||||
return paused; |
||||
} |
||||
} |
||||
|
||||
public delegate void FinishedHandler(bool manual); |
||||
public event FinishedHandler Finished; |
||||
|
||||
IEnumerator coroutine; |
||||
bool running; |
||||
bool paused; |
||||
bool stopped; |
||||
|
||||
public TaskState(IEnumerator c) |
||||
{ |
||||
coroutine = c; |
||||
} |
||||
|
||||
public void Pause() |
||||
{ |
||||
paused = true; |
||||
} |
||||
|
||||
public void Unpause() |
||||
{ |
||||
paused = false; |
||||
} |
||||
|
||||
public void Start() |
||||
{ |
||||
running = true; |
||||
singleton.StartCoroutine(CallWrapper()); |
||||
} |
||||
|
||||
public void Stop() |
||||
{ |
||||
stopped = true; |
||||
running = false; |
||||
} |
||||
|
||||
IEnumerator CallWrapper() |
||||
{ |
||||
yield return null; |
||||
IEnumerator e = coroutine; |
||||
while(running) { |
||||
if(paused) |
||||
yield return null; |
||||
else { |
||||
if(e != null && e.MoveNext()) { |
||||
yield return e.Current; |
||||
} |
||||
else { |
||||
running = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
FinishedHandler handler = Finished; |
||||
if(handler != null) |
||||
handler(stopped); |
||||
} |
||||
} |
||||
|
||||
static TaskManager singleton; |
||||
|
||||
public static TaskState CreateTask(IEnumerator coroutine) |
||||
{ |
||||
if(singleton == null) { |
||||
GameObject go = new GameObject("TaskManager"); |
||||
singleton = go.AddComponent<TaskManager>(); |
||||
} |
||||
return new TaskState(coroutine); |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 12a405989c9fd46e3924b54166aa0e4c |
||||
timeCreated: 1454589006 |
||||
licenseType: Free |
||||
MonoImporter: |
||||
serializedVersion: 2 |
||||
defaultReferences: [] |
||||
executionOrder: 0 |
||||
icon: {instanceID: 0} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 8ab8afbfde36d4bc4ac6615dba9b64f9 |
||||
folderAsset: yes |
||||
timeCreated: 1458925240 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: b8cbda23563c24ee493cae4e639ed67e |
||||
folderAsset: yes |
||||
timeCreated: 1456153619 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: cadf03bc0402c437fafc9762bfb14663 |
||||
timeCreated: 1456153613 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 3f657bc2681724af29e56b16b97d9ed1 |
||||
timeCreated: 1455270559 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 49de283ddba5a4377a7a78f199f82d7e |
||||
folderAsset: yes |
||||
timeCreated: 1455889299 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 33a4676250b33487eb5c027888e492a7 |
||||
folderAsset: yes |
||||
timeCreated: 1455889308 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
local M = {} |
||||
|
||||
M.hello = |
||||
{ |
||||
en = "Hi there", |
||||
fr = "Bonjour" |
||||
} |
||||
|
||||
return M; |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 9900570d789fa4b29957e4b897af9e3b |
||||
timeCreated: 1455889334 |
||||
licenseType: Free |
||||
TextScriptImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
fileFormatVersion: 2 |
||||
guid: d2ab1fbe555d44e9e870311657856bdc |
||||
timeCreated: 1456156794 |
||||
licenseType: Free |
||||
AudioImporter: |
||||
serializedVersion: 6 |
||||
defaultSettings: |
||||
loadType: 0 |
||||
sampleRateSetting: 0 |
||||
sampleRateOverride: 44100 |
||||
compressionFormat: 1 |
||||
quality: 1 |
||||
conversionMode: 0 |
||||
platformSettingOverrides: {} |
||||
forceToMono: 0 |
||||
normalize: 1 |
||||
preloadAudioData: 1 |
||||
loadInBackground: 0 |
||||
3D: 1 |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 29e05612baa3440c9966497e70e5f03c |
||||
folderAsset: yes |
||||
timeCreated: 1456417871 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,138 @@
|
||||
%YAML 1.1 |
||||
%TAG !u! tag:unity3d.com,2011: |
||||
--- !u!21 &2100000 |
||||
Material: |
||||
serializedVersion: 6 |
||||
m_ObjectHideFlags: 0 |
||||
m_PrefabParentObject: {fileID: 0} |
||||
m_PrefabInternal: {fileID: 0} |
||||
m_Name: TestMaterial |
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} |
||||
m_ShaderKeywords: |
||||
m_LightmapFlags: 5 |
||||
m_CustomRenderQueue: -1 |
||||
stringTagMap: {} |
||||
m_SavedProperties: |
||||
serializedVersion: 2 |
||||
m_TexEnvs: |
||||
data: |
||||
first: |
||||
name: _MainTex |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _BumpMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _DetailNormalMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _ParallaxMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _OcclusionMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _EmissionMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _DetailMask |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _DetailAlbedoMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
data: |
||||
first: |
||||
name: _MetallicGlossMap |
||||
second: |
||||
m_Texture: {fileID: 0} |
||||
m_Scale: {x: 1, y: 1} |
||||
m_Offset: {x: 0, y: 0} |
||||
m_Floats: |
||||
data: |
||||
first: |
||||
name: _SrcBlend |
||||
second: 1 |
||||
data: |
||||
first: |
||||
name: _DstBlend |
||||
second: 0 |
||||
data: |
||||
first: |
||||
name: _Cutoff |
||||
second: 0.5 |
||||
data: |
||||
first: |
||||
name: _Parallax |
||||
second: 0.02 |
||||
data: |
||||
first: |
||||
name: _ZWrite |
||||
second: 1 |
||||
data: |
||||
first: |
||||
name: _Glossiness |
||||
second: 0.5 |
||||
data: |
||||
first: |
||||
name: _BumpScale |
||||
second: 1 |
||||
data: |
||||
first: |
||||
name: _OcclusionStrength |
||||
second: 1 |
||||
data: |
||||
first: |
||||
name: _DetailNormalMapScale |
||||
second: 1 |
||||
data: |
||||
first: |
||||
name: _UVSec |
||||
second: 0 |
||||
data: |
||||
first: |
||||
name: _Mode |
||||
second: 0 |
||||
data: |
||||
first: |
||||
name: _Metallic |
||||
second: 0 |
||||
m_Colors: |
||||
data: |
||||
first: |
||||
name: _EmissionColor |
||||
second: {r: 0, g: 0, b: 0, a: 1} |
||||
data: |
||||
first: |
||||
name: _Color |
||||
second: {r: 1, g: 1, b: 1, a: 1} |
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2 |
||||
guid: 97a4dac23b6bb49888243026c50076a9 |
||||
timeCreated: 1456417879 |
||||
licenseType: Free |
||||
NativeFormatImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2 |
||||
guid: ecd214168ef7d46948192ac5b15df61c |
||||
folderAsset: yes |
||||
timeCreated: 1456418449 |
||||
licenseType: Free |
||||
DefaultImporter: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,57 @@
|
||||
fileFormatVersion: 2 |
||||
guid: efe8aa62cc87f4b70b9272e4e8e06668 |
||||
timeCreated: 1456418478 |
||||
licenseType: Free |
||||
TextureImporter: |
||||
fileIDToRecycleName: {} |
||||
serializedVersion: 2 |
||||
mipmaps: |
||||
mipMapMode: 0 |
||||
enableMipMap: 1 |
||||
linearTexture: 0 |
||||
correctGamma: 0 |
||||
fadeOut: 0 |
||||
borderMipMap: 0 |
||||
mipMapFadeDistanceStart: 1 |
||||
mipMapFadeDistanceEnd: 3 |
||||
bumpmap: |
||||
convertToNormalMap: 0 |
||||
externalNormalMap: 0 |
||||
heightScale: 0.25 |
||||
normalMapFilter: 0 |
||||
isReadable: 0 |
||||
grayScaleToAlpha: 0 |
||||
generateCubemap: 0 |
||||
cubemapConvolution: 0 |
||||
cubemapConvolutionSteps: 8 |
||||
cubemapConvolutionExponent: 1.5 |
||||
seamlessCubemap: 0 |
||||
textureFormat: -3 |
||||
maxTextureSize: 2048 |
||||
textureSettings: |
||||
filterMode: -1 |
||||
aniso: 16 |
||||
mipBias: -1 |
||||
wrapMode: 1 |
||||
nPOTScale: 1 |
||||
lightmap: 0 |
||||
rGBM: 0 |
||||
compressionQuality: 50 |
||||
allowsAlphaSplitting: 0 |
||||
spriteMode: 0 |
||||
spriteExtrude: 1 |
||||
spriteMeshType: 1 |
||||
alignment: 0 |
||||
spritePivot: {x: 0.5, y: 0.5} |
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
||||
spritePixelsToUnits: 100 |
||||
alphaIsTransparency: 0 |
||||
textureType: 0 |
||||
buildTargetSettings: [] |
||||
spriteSheet: |
||||
sprites: [] |
||||
outline: [] |
||||
spritePackingTag: |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
Loading…
Reference in new issue