package bms.player.beatoraja.skin.lr2; import java.io.*; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.logging.Logger; import java.util.stream.Stream; import static bms.player.beatoraja.skin.SkinProperty.*; import bms.model.Mode; import bms.player.beatoraja.*; import bms.player.beatoraja.SkinConfig.Offset; import bms.player.beatoraja.play.PlaySkin; import bms.player.beatoraja.play.SkinGauge; import bms.player.beatoraja.play.bga.BGAProcessor; import bms.player.beatoraja.select.MusicSelectSkin; import bms.player.beatoraja.skin.*; import bms.player.beatoraja.skin.SkinHeader.*; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.IntIntMap; import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.ObjectMap; /** * LR2のスキン定義用csvファイルのローダー * * @author exch */ public abstract class LR2SkinCSVLoader<S extends Skin> extends LR2SkinLoader { Array<Object> imagelist = new Array<Object>(); Array<SkinTextImage.SkinTextImageSource> fontlist = new Array<SkinTextImage.SkinTextImageSource>(); /** * スキンの元サイズ */ public final Resolution src; /** * 描画サイズ */ public final Resolution dst; private boolean usecim; private String skinpath; protected S skin; private MainState state; public LR2SkinCSVLoader(Resolution src, Config c) { this.src = src; this.dst = c.getResolution(); usecim = c.isCacheSkinImage(); skinpath = c.getSkinpath(); final float srcw = src.width; final float srch = src.height; final float dstw = dst.width; final float dsth = dst.height; addCommandWord(CSVCommand.values()); addCommandWord(new CommandWord("INCLUDE") { @Override public void execute(String[] str) { final File imagefile = LR2SkinLoader.getPath(skinpath, str[1], filemap); if (imagefile.exists()) { try (BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream(imagefile), "MS932"));) { while ((line = br.readLine()) != null) { processLine(line, state); } } catch (IOException e) { e.printStackTrace(); } } } }); addCommandWord(new CommandWord("IMAGE") { @Override public void execute(String[] str) { final File imagefile = LR2SkinLoader.getPath(skinpath, str[1], filemap); if (imagefile.exists()) { boolean isMovie = false; for (String mov : BGAProcessor.mov_extension) { if (imagefile.getName().toLowerCase().endsWith(mov)) { try { SkinSourceMovie mm = new SkinSourceMovie(imagefile.getPath()); imagelist.add(mm); isMovie = true; break; } catch (Throwable e) { Logger.getGlobal().warning("BGAファイル読み込み失敗。" + e.getMessage()); e.printStackTrace(); } } } if (!isMovie) { imagelist.add(getTexture(imagefile.getPath(), usecim)); } } else { Logger.getGlobal() .warning("IMAGE " + imagelist.size + " : ファイルが見つかりません : " + imagefile.getPath()); imagelist.add(null); } // System.out // .println("Image Loaded - " + (imagelist.size() - // 1) + " : " + imagefile.getPath()); } }); addCommandWord(new CommandWord("LR2FONT") { @Override public void execute(String[] str) { final File imagefile = LR2SkinLoader.getPath(skinpath, str[1], filemap); if (imagefile.exists()) { LR2FontLoader font = new LR2FontLoader(usecim); try { SkinTextImage.SkinTextImageSource source = font.loadFont(imagefile.toPath()); fontlist.add(source); } catch (IOException e) { e.printStackTrace(); fontlist.add(null); } } else { Logger.getGlobal() .warning("IMAGE " + imagelist.size + " : ファイルが見つかりません : " + imagefile.getPath()); fontlist.add(null); } // System.out // .println("Image Loaded - " + (imagelist.size() - // 1) + " : " + imagefile.getPath()); } }); addCommandWord(new CommandWord("SRC_IMAGE") { @Override public void execute(String[] str) { part = null; int gr = Integer.parseInt(str[2]); if (gr >= 100) { part = new SkinImage(gr); // System.out.println("add reference image : " // + gr); } else { int[] values = parseInt(str); if (values[2] < imagelist.size && imagelist.get(values[2]) != null && imagelist.get(values[2]) instanceof SkinSourceMovie) { part = new SkinImage((SkinSourceMovie) imagelist.get(values[2])); } else { TextureRegion[] images = getSourceImage(values); if (images != null) { part = new SkinImage(images, values[10], values[9]); // System.out.println("Object Added - " + // (part.getTiming())); } } } if (part != null) { skin.add(part); } } }); addCommandWord(new CommandWord("IMAGESET") { @Override public void execute(String[] str) { int gr = Integer.parseInt(str[2]); if (gr < imagelist.size && imagelist.get(gr) != null) { int[] values = parseInt(str); imagesetarray.add(getSourceImage(values)); } } }); addCommandWord(new CommandWord("SRC_IMAGESET") { @Override public void execute(String[] str) { int[] values = parseInt(str); TextureRegion[][] tr = new TextureRegion[values[4]][]; for (int i = 0; i < values[4]; i++) { tr[i] = (TextureRegion[]) imagesetarray.get(values[5+i]); } part = new SkinImage(tr, values[2], values[1]); part.setReferenceID(values[3]); if (part != null) { skin.add(part); } } }); addCommandWord(new CommandWord("DST_IMAGE") { @Override public void execute(String[] str) { if (part != null) { int[] values = parseInt(str); if (values[5] < 0) { values[3] += values[5]; values[5] = -values[5]; } if (values[6] < 0) { values[4] += values[6]; values[6] = -values[6]; } part.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); part.setStretch(stretch); } } }); addCommandWord(new CommandWord("SRC_NUMBER") { //#SRC_NUMBER,(NULL),gr,x,y,w,h,div_x,div_y,cycle,timer,num,align,keta,zeropadding @Override public void execute(String[] str) { num = null; int[] values = parseInt(str); final int divx = values[7] > 0 ? values[7] : 1; final int divy = values[8] > 0 ? values[8] : 1; if (divx * divy >= 10) { TextureRegion[] images = getSourceImage(values); if (images != null) { if (images.length % 24 == 0) { TextureRegion[][] pn = new TextureRegion[images.length / 24][]; TextureRegion[][] mn = new TextureRegion[images.length / 24][]; for (int j = 0; j < pn.length; j++) { pn[j] = new TextureRegion[12]; mn[j] = new TextureRegion[12]; for (int i = 0; i < 12; i++) { pn[j][i] = images[j * 24 + i]; mn[j][i] = images[j * 24 + i + 12]; } } num = new SkinNumber(pn, mn, values[10], values[9], values[13] + 1, str[14].length() > 0 ? values[14] : 2, values[15], values[11]); num.setAlign(values[12]); } else { int d = images.length % 10 == 0 ? 10 : 11; TextureRegion[][] nimages = new TextureRegion[divx * divy / d][d]; for (int i = 0; i < d; i++) { for (int j = 0; j < divx * divy / d; j++) { nimages[j][i] = images[j * d + i]; } } num = new SkinNumber(nimages, values[10], values[9], values[13], d > 10 ? 2 : 0, values[15], values[11]); num.setAlign(values[12]); } skin.add(num); // System.out.println("Number Added - " + // (num.getId())); } } } }); addCommandWord(new CommandWord("DST_NUMBER") { @Override public void execute(String[] str) { if (num != null) { int[] values = parseInt(str); num.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("SRC_TEXT") { @Override public void execute(String[] str) { text = null; int[] values = parseInt(str); if (values[2] < fontlist.size && fontlist.get(values[2]) != null) { text = new SkinTextImage(fontlist.get(values[2]), values[3]); } else { text = new SkinTextFont("skin/default/VL-Gothic-Regular.ttf", 0, 48, 2); } text.setAlign(values[4]); text.setEditable(values[5] != 0); int panel = values[6]; skin.add(text); if(text.isEditable() && values[3] == SkinProperty.STRING_SEARCHWORD && skin instanceof MusicSelectSkin) { ((MusicSelectSkin) skin).searchText = text; } // System.out.println("Text Added - " + // (values[3])); } }); addCommandWord(new CommandWord("DST_TEXT") { @Override public void execute(String[] str) { if (text != null) { int[] values = parseInt(str); text.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); if(skin instanceof MusicSelectSkin && ((MusicSelectSkin) skin).searchText == text) { Rectangle r = new Rectangle(values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch); ((MusicSelectSkin) skin).setSearchTextRegion(r); } } } }); addCommandWord(new CommandWord("SRC_SLIDER") { @Override public void execute(String[] str) { slider = null; int[] values = parseInt(str); TextureRegion[] images = getSourceImage(values); if (images != null) { slider = new SkinSlider(images, values[10], values[9], values[11], (int) (values[12] * (values[11] == 1 || values[11] == 3 ? (dstw / srcw) : (dsth / srch))), values[13]); slider.setChangeable(values[14] == 0); skin.add(slider); // TODO 固有実装の汎用化 if((skin instanceof PlaySkin) && values[13] == SLIDER_LANECOVER) { ((PlaySkin)skin).laneCover = slider; } // System.out.println("Object Added - " + // (part.getTiming())); } } }); addCommandWord(new CommandWord("SRC_SLIDER_REFNUMBER") { //NUMBER値参照版 //#SRC_SLIDER_REFNUMBER,(NULL),gr,x,y,w,h,div_x,div_y,cycle,timer,muki,range,type,disable,min_value,max_value @Override public void execute(String[] str) { slider = null; int[] values = parseInt(str); TextureRegion[] images = getSourceImage(values); if (images != null) { slider = new SkinSlider(images, values[10], values[9], values[11], (int) (values[12] * (values[11] == 1 || values[11] == 3 ? (dstw / srcw) : (dsth / srch))), values[13], values[15], values[16]); slider.setChangeable(values[14] == 0); skin.add(slider); // System.out.println("Object Added - " + // (part.getTiming())); } } }); addCommandWord(new CommandWord("DST_SLIDER") { @Override public void execute(String[] str) { if (slider != null) { int[] values = parseInt(str); slider.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("SRC_BARGRAPH") { @Override public void execute(String[] str) { bar = null; int[] values = parseInt(str); int gr = values[2]; if (gr >= 100) { bar = new SkinGraph(gr, values[11] + 100); bar.setDirection(values[12]); } else { TextureRegion[] images = getSourceImage(values); if (images != null) { bar = new SkinGraph(images, values[10], values[9],values[11] + 100); bar.setDirection(values[12]); // System.out.println("Object Added - " + // (part.getTiming())); } } if (bar != null) { skin.add(bar); } } }); addCommandWord(new CommandWord("SRC_BARGRAPH_REFNUMBER") { //NUMBER値参照版 //#SRC_BARGRAPH_REFNUMBER,(NULL),gr,x,y,w,h,div_x,div_y,cycle,timer,type,muki,min_value,max_value @Override public void execute(String[] str) { bar = null; int[] values = parseInt(str); int gr = values[2]; if (gr >= 100) { bar = new SkinGraph(gr,values[11],values[13],values[14]); bar.setDirection(values[12]); } else { TextureRegion[] images = getSourceImage(values); if (images != null) { bar = new SkinGraph(images,values[10], values[9], values[11],values[13],values[14]); bar.setDirection(values[12]); // System.out.println("Object Added - " + // (part.getTiming())); } } if (bar != null) { skin.add(bar); } } }); addCommandWord(new CommandWord("DST_BARGRAPH") { @Override public void execute(String[] str) { if (bar != null) { int[] values = parseInt(str); if (bar.getDirection() == 1) { values[4] += values[6]; values[6] = -values[6]; } bar.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("SRC_BUTTON") { @Override public void execute(String[] str) { button = null; int gr = Integer.parseInt(str[2]); if (gr < imagelist.size && imagelist.get(gr) != null) { int[] values = parseInt(str); int x = values[3]; int y = values[4]; int w = values[5]; if (w == -1) { w = ((Texture) imagelist.get(gr)).getWidth(); } int h = values[6]; if (h == -1) { h = ((Texture) imagelist.get(gr)).getHeight(); } final int divx = values[7] > 0 ? values[7] : 1; final int divy = values[8] > 0 ? values[8] : 1; TextureRegion[][] tr; int length = values[15]; if (length <= 0) { tr = new TextureRegion[divx * divy][]; for (int i = 0; i < divx; i++) { for (int j = 0; j < divy; j++) { tr[divx * j + i] = new TextureRegion[] { new TextureRegion((Texture) imagelist.get(gr), x + w / divx * i, y + h / divy * j, w / divx, h / divy) }; } } }else { tr = new TextureRegion[length][]; TextureRegion[] srcimg = getSourceImage(values); for (int i = 0; i < tr.length; i++) { tr[i] = new TextureRegion[srcimg.length / length]; for (int j = 0; j < tr[i].length; j++) { tr[i][j] = srcimg[i * tr[i].length + j]; } } } button = new SkinImage(tr, values[10], values[9]); button.setReferenceID(values[11]); if (values[12] == 1) { button.setClickevent(values[11]); button.setClickeventType(values[14] > 0 ? 0 : values[14] < 0 ? 1 : 2); } skin.add(button); // System.out.println("Object Added - " + // (part.getTiming())); } } }); addCommandWord(new CommandWord("DST_BUTTON") { @Override public void execute(String[] str) { if (button != null) { int[] values = parseInt(str); button.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("SRC_ONMOUSE") { @Override public void execute(String[] str) { onmouse = null; int gr = Integer.parseInt(str[2]); if (gr < imagelist.size && imagelist.get(gr) != null) { int[] values = parseInt(str); TextureRegion[] images = getSourceImage(values); if (images != null) { onmouse = new SkinImage(images, values[10], values[9]); skin.setMouseRect(onmouse, values[12], values[6] - values[13] - values[15], values[14], values[15]); skin.add(onmouse); } } } }); addCommandWord(new CommandWord("DST_ONMOUSE") { @Override public void execute(String[] str) { if (onmouse != null) { int[] values = parseInt(str); onmouse.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("SRC_GROOVEGAUGE") { //SRC定義,index,gr,x,y,w,h,div_x,div_y,cycle,timer,add_x,add_y,parts,animation_type,animation_range,animation_cycle,starttime,endtime //parts:粒数 animation_type:アニメーションの種類(0:RANDOM 1:INCLEASE 2:DECLEASE 3:PMS用明滅アニメーション) //animation_range:アニメーションする範囲 animation_cycle:アニメーション間隔(ms) //starttime, endtime:リザルト用 ゲージが0から曲終了時の値まで増える演出の開始時間・終了時間(ms) @Override public void execute(String[] str) { gauger = null; int[] values = parseInt(str); if (values[2] < imagelist.size && imagelist.get(values[2]) != null) { int playside = values[1]; final int divx = values[7] > 0 ? values[7] : 1; final int divy = values[8] > 0 ? values[8] : 1; TextureRegion[][] gauge; if(values[14] == 3 && divx * divy % 6 == 0) { //アニメーションタイプがPMS用明滅アニメーションの場合 表赤、表緑、裏赤、裏緑、発光表赤、発光表緑の順にsrc分割 gauge = new TextureRegion[(divx * divy) / 6][36]; final int w = values[5]; final int h = values[6]; for (int x = 0; x < divx; x++) { for (int y = 0; y < divy; y++) { if ((y * divx + x) / 6 < gauge.length) { TextureRegion tr = new TextureRegion( (Texture) imagelist.get(values[2]), values[3] + w * x / divx, values[4] + h * y / divy, w / divx, h / divy); final int dx = (y * divx + x) / 6; final int dy = (y * divx + x) % 6; gauge[dx][dy] = gauge[dx][dy + 6] = gauge[dx][dy + 12] = gauge[dx][dy + 18] = gauge[dx][dy + 24] = gauge[dx][dy + 30] = tr; } } } } else { gauge = new TextureRegion[(divx * divy) / 4][36]; final int w = values[5]; final int h = values[6]; for (int x = 0; x < divx; x++) { for (int y = 0; y < divy; y++) { if ((y * divx + x) / 4 < gauge.length) { TextureRegion tr = new TextureRegion( (Texture) imagelist.get(values[2]), values[3] + w * x / divx, values[4] + h * y / divy, w / divx, h / divy); final int dx = (y * divx + x) / 4; final int dy = (y * divx + x) % 4; gauge[dx][dy] = gauge[dx][dy + 6] = gauge[dx][dy + 12] = gauge[dx][dy + 18] = gauge[dx][dy + 24] = gauge[dx][dy + 30] = tr; if(dy < 2) { gauge[dx][dy + 4] = gauge[dx][dy + 10] = gauge[dx][dy + 16] = gauge[dx][dy + 22] = gauge[dx][dy + 28] = gauge[dx][dy + 34] = tr; } } } } } groovex = values[11]; groovey = values[12]; if (gauger == null) { if(values[13] == 0) { gauger = new SkinGauge(gauge, values[10], values[9], mode == Mode.POPN_9K ? 24 : 50, 0, mode == Mode.POPN_9K ? 0 : 3, 33); } else { gauger = new SkinGauge(gauge, values[10], values[9], values[13], values[14], values[15], values[16]); } gauger.setStarttime(values[17]); gauger.setEndtime(values[18]); skin.add(gauger); } } } }); addCommandWord(new CommandWord("SRC_GROOVEGAUGE_EX") { //SRC定義,index,gr,x,y,w,h,div_x,div_y,cycle,timer,add_x,add_y,parts,animation_type,animation_range,animation_cycle,starttime,endtime //JSONスキンと同形式版 表赤、表緑、裏赤、裏緑、EX表赤、EX表緑、EX裏赤、EX裏緑の順にsrc分割 //parts:粒数 animation_type:アニメーションの種類(0:RANDOM 1:INCLEASE 2:DECLEASE 3:PMS用明滅アニメーション) //animation_range:アニメーションする範囲 animation_cycle:アニメーション間隔(ms) //starttime, endtime:リザルト用 ゲージが0から曲終了時の値まで増える演出の開始時間・終了時間(ms @Override public void execute(String[] str) { gauger = null; int[] values = parseInt(str); if (values[2] < imagelist.size && imagelist.get(values[2]) != null) { int playside = values[1]; final int divx = values[7] > 0 ? values[7] : 1; final int divy = values[8] > 0 ? values[8] : 1; TextureRegion[][] gauge; if(values[14] == 3 && divx * divy % 12 == 0) { //アニメーションタイプがPMS用明滅アニメーションの場合 表赤、表緑、裏赤、裏緑、EX表赤、EX表緑、EX裏赤、EX裏緑、発光表赤、発光表緑、発光EX表赤、発光EX表緑の順にsrc分割 gauge = new TextureRegion[(divx * divy) / 12][36]; final int w = values[5]; final int h = values[6]; for (int x = 0; x < divx; x++) { for (int y = 0; y < divy; y++) { if ((y * divx + x) / 12 < gauge.length) { TextureRegion tr = new TextureRegion( (Texture) imagelist.get(values[2]), values[3] + w * x / divx, values[4] + h * y / divy, w / divx, h / divy); final int dx = (y * divx + x) / 12; final int dy = (y * divx + x) % 12; if(dy < 4) { gauge[dx][dy] = gauge[dx][dy + 6] = gauge[dx][dy + 12] = gauge[dx][dy + 18] = tr; } else if(dy >= 4 && dy < 8){ gauge[dx][dy + 20] = gauge[dx][dy + 26] = tr; } else if(dy == 8 || dy == 9) { gauge[dx][dy - 4] = gauge[dx][dy + 2] = gauge[dx][dy + 8] = gauge[dx][dy + 14] = tr; } else { gauge[dx][dy + 18] = gauge[dx][dy + 24] = tr; } } } } } else { gauge = new TextureRegion[(divx * divy) / 8][36]; final int w = values[5]; final int h = values[6]; for (int x = 0; x < divx; x++) { for (int y = 0; y < divy; y++) { if ((y * divx + x) / 8 < gauge.length) { TextureRegion tr = new TextureRegion( (Texture) imagelist.get(values[2]), values[3] + w * x / divx, values[4] + h * y / divy, w / divx, h / divy); final int dx = (y * divx + x) / 8; final int dy = (y * divx + x) % 8; if(dy < 4) { gauge[dx][dy] = gauge[dx][dy + 6] = gauge[dx][dy + 12] = gauge[dx][dy + 18] = tr; if(dy < 2) { gauge[dx][dy + 4] = gauge[dx][dy + 10] = gauge[dx][dy + 16] = gauge[dx][dy + 22] = tr; } } else { gauge[dx][dy + 20] = gauge[dx][dy + 26] = tr; if(dy < 6) { gauge[dx][dy + 24] = gauge[dx][dy + 30] = tr; } } } } } } groovex = values[11]; groovey = values[12]; if (gauger == null) { if(values[13] == 0) { gauger = new SkinGauge(gauge, values[10], values[9], mode == Mode.POPN_9K ? 24 : 50, 0, mode == Mode.POPN_9K ? 0 : 3, 33); } else { gauger = new SkinGauge(gauge, values[10], values[9], values[13], values[14], values[15], values[16]); } gauger.setStarttime(values[17]); gauger.setEndtime(values[18]); skin.add(gauger); } } } }); addCommandWord(new CommandWord("DST_GROOVEGAUGE") { @Override public void execute(String[] str) { if (gauger != null) { float width = (Math.abs(groovex) >= 1) ? (groovex * 50 * dstw / srcw) : (Integer.parseInt(str[5]) * dstw / srcw); float height = (Math.abs(groovey) >= 1) ? (groovey * 50 * dsth / srch) : (Integer.parseInt(str[6]) * dsth / srch); float x = Integer.parseInt(str[3]) * dstw / srcw - (groovex < 0 ? groovex * dstw / srcw : 0); float y = dsth - Integer.parseInt(str[4]) * dsth / srch - height; int[] values = parseInt(str); gauger.setDestination(values[2], x, y, width, height, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("DST_PM_CHARA_1P") { @Override public void execute(String[] str) { //プレイ用 判定連動 //x,y,w,h,color,offset,folderpath int[] values = parseInt(str); if (values[3] < 0) { values[1] += values[3]; values[3] = -values[3]; } if (values[4] < 0) { values[2] += values[4]; values[4] = -values[4]; } final File imagefile = LR2SkinLoader.getPath(skinpath, str[7], filemap); new PomyuCharaLoader(skin).load(usecim, imagefile, 0, (values[5] == 1 || values[5] == 2) ? values[5] : 1, values[1] * dstw / srcw, dsth - (values[2] + values[4]) * dsth / srch, values[3] * dstw / srcw, values[4] * dsth / srch, 1, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, values[6]); } }); addCommandWord(new CommandWord("DST_PM_CHARA_2P") { @Override public void execute(String[] str) { //プレイ用 判定連動 //x,y,w,h,color,offset,folderpath int[] values = parseInt(str); if (values[3] < 0) { values[1] += values[3]; values[3] = -values[3]; } if (values[4] < 0) { values[2] += values[4]; values[4] = -values[4]; } final File imagefile = LR2SkinLoader.getPath(skinpath, str[7], filemap); new PomyuCharaLoader(skin).load(usecim, imagefile, 0, (values[5] == 1 || values[5] == 2) ? values[5] : 1, values[1] * dstw / srcw, dsth - (values[2] + values[4]) * dsth / srch, values[3] * dstw / srcw, values[4] * dsth / srch, 2, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, values[6]); } }); addCommandWord(new CommandWord("DST_PM_CHARA_ANIMATION") { @Override public void execute(String[] str) { //プレイ以外用 判定非連動 //x,y,w,h,color,animationtype,timer,op1,op2,op3,offset,folderpath //type 0:NEUTRAL 1:FEVER 2:GREAT 3:GOOD 4:BAD 5:FEVERWIN 6:WIN 7:LOSE 8:OJAMA 9:DANCE int[] values = parseInt(str); if(values[6] >= 0 && values[6] <= 9) { if (values[3] < 0) { values[1] += values[3]; values[3] = -values[3]; } if (values[4] < 0) { values[2] += values[4]; values[4] = -values[4]; } final File imagefile = LR2SkinLoader.getPath(skinpath, str[12], filemap); new PomyuCharaLoader(skin).load(usecim, imagefile, values[6] + 6, (values[5] == 1 || values[5] == 2) ? values[5] : 1, values[1] * dstw / srcw, dsth - (values[2] + values[4]) * dsth / srch, values[3] * dstw / srcw, values[4] * dsth / srch, Integer.MIN_VALUE, values[7], values[8], values[9], values[10], values[11]); } } }); addCommandWord(new CommandWord("SRC_PM_CHARA_IMAGE") { @Override public void execute(String[] str) { //color,type,folderpath //type 0:キャラ背景 1:名前画像 2:ハリアイ画像(上半身のみ) 3:ハリアイ画像(全体) 4:キャラアイコン PMcharaPart = null; int[] values = parseInt(str); if(values[2] >= 0 && values[2] <= 4) { final File imagefile = LR2SkinLoader.getPath(skinpath, str[3], filemap); PMcharaPart = new PomyuCharaLoader(skin).load(usecim, imagefile, values[2] + 1, (values[1] == 1 || values[1] == 2) ? values[1] : 1, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); } } }); addCommandWord(new CommandWord("DST_PM_CHARA_IMAGE") { @Override public void execute(String[] str) { //DST_IMAGEと同様 if (PMcharaPart != null) { int[] values = parseInt(str); if (values[5] < 0) { values[3] += values[5]; values[5] = -values[5]; } if (values[6] < 0) { values[4] += values[6]; values[6] = -values[6]; } PMcharaPart.setDestination(values[2], values[3] * dstw / srcw, dsth - (values[4] + values[6]) * dsth / srch, values[5] * dstw / srcw, values[6] * dsth / srch, values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15], values[16], values[17], values[18], values[19], values[20], readOffset(str, 21)); } } }); addCommandWord(new CommandWord("STRETCH") { @Override public void execute(String[] str) { int[] values = parseInt(str); stretch = values[1]; } }); } protected void loadSkin(Skin skin, Path f, MainState state) throws IOException { this.loadSkin(skin, f, state, new IntIntMap()); } protected void loadSkin(Skin skin, Path f, MainState state, IntIntMap option) throws IOException { this.loadSkin0(skin, f, state, option); } private ObjectMap<String, String> filemap = new ObjectMap<String, String>(); protected S loadSkin(S skin, Path f, MainState state, SkinHeader header, IntIntMap option, ObjectMap<String, Object> property) throws IOException { this.skin = skin; this.state = state; for (String key : property.keys()) { if (property.get(key) != null) { if (property.get(key) instanceof Integer) { op.put((Integer) property.get(key), 1); } if (property.get(key) instanceof String) { for (CustomFile file : header.getCustomFiles()) { if (file.name.equals(key)) { filemap.put(file.path, (String) property.get(key)); break; } } } } } IntMap<SkinConfig.Offset> offset = new IntMap<>(); for (CustomOffset of : header.getCustomOffsets()) { final Object o = property.get(of.name); if(o instanceof Offset) { offset.put(of.id, (Offset)o); } } skin.setOffset(offset); op.putAll(option); this.loadSkin0(skin, f, state, op); return skin; } SkinImage part = null; SkinImage button = null; SkinImage onmouse = null; SkinGraph bar = null; SkinSlider slider = null; SkinNumber num = null; SkinText text = null; String line = null; SkinImage PMcharaPart = null; SkinGauge gauger = null; int groovex = 0; int groovey = 0; Mode mode; Array<Object> imagesetarray = new Array<Object>(); int stretch = -1; protected void loadSkin0(Skin skin, Path f, MainState state, IntIntMap option) throws IOException { try (Stream<String> lines = Files.lines(f, Charset.forName("MS932"))) { lines.forEach(line -> { try { processLine(line, state); } catch (Throwable e) { e.printStackTrace(); } }); }; skin.setOption(option); for (SkinObject obj : skin.getAllSkinObjects()) { if (obj instanceof SkinImage && obj.getAllDestination().length == 0) { skin.removeSkinObject(obj); Logger.getGlobal().warning("NO_DESTINATION : " + obj); } } } protected int[] parseInt(String[] s) { int[] result = new int[22]; for (int i = 1; i < result.length && i < s.length; i++) { try { result[i] = Integer.parseInt(s[i].replace('!', '-').replaceAll(" ", "")); } catch (Exception e) { } } return result; } protected int[] readOffset(String[] str, int startIndex) { return readOffset(str, startIndex, new int[0]); } protected int[] readOffset(String[] str, int startIndex, int[] offset) { IntArray result = new IntArray(); for(int i : offset) { result.add(i); } for (int i = startIndex; i < str.length; i++) { String s = str[i].replaceAll("[^0-9-]", ""); if(s.length() > 0) { result.add(Integer.parseInt(s)); } } return result.toArray(); } protected TextureRegion[] getSourceImage(int[] values) { if (values[2] < imagelist.size && imagelist.get(values[2]) != null && imagelist.get(values[2]) instanceof Texture) { return getSourceImage((Texture) imagelist.get(values[2]), values[3], values[4], values[5], values[6], values[7], values[8]); } Logger.getGlobal().warning("IMAGEが定義されてないか、読み込みに失敗しています : " + line); return null; } protected TextureRegion[] getSourceImage(Texture image, int x, int y, int w, int h, int divx, int divy) { if (w == -1) { w = image.getWidth(); } if (h == -1) { h = image.getHeight(); } if (divx <= 0) { divx = 1; } if (divy <= 0) { divy = 1; } TextureRegion[] images = new TextureRegion[divx * divy]; for (int i = 0; i < divx; i++) { for (int j = 0; j < divy; j++) { images[divx * j + i] = new TextureRegion(image, x + w / divx * i, y + h / divy * j, w / divx, h / divy); } } return images; } public S loadSkin(Path f, MainState state, SkinHeader header, IntIntMap option, SkinConfig.Property property) throws IOException { ObjectMap m = new ObjectMap(); for(SkinConfig.Option op : property.getOption()) { if(op.value != OPTION_RANDOM_VALUE) { m.put(op.name, op.value); } else { for (CustomOption opt : header.getCustomOptions()) { if(op.name.equals(opt.name)) { if(header.getRandomSelectedOptions(op.name) >= 0) m.put(op.name, header.getRandomSelectedOptions(op.name)); } } } } for(SkinConfig.FilePath file : property.getFile()) { if(!file.path.equals("Random")) { m.put(file.name, file.path); } else { for (CustomFile cf : header.getCustomFiles()) { if(file.name.equals(cf.name)) { String ext = cf.path.substring(cf.path.lastIndexOf("*") + 1); if(cf.path.contains("|")) { if(cf.path.length() > cf.path.lastIndexOf('|') + 1) { ext = cf.path.substring(cf.path.lastIndexOf("*") + 1, cf.path.indexOf('|')) + cf.path.substring(cf.path.lastIndexOf('|') + 1); } else { ext = cf.path.substring(cf.path.lastIndexOf("*") + 1, cf.path.indexOf('|')); } } final int slashindex = cf.path.lastIndexOf('/'); File dir = slashindex != -1 ? new File(cf.path.substring(0, slashindex)) : new File(cf.path); if (dir.exists() && dir.isDirectory()) { Array<File> l = new Array<File>(); for (File subfile : dir.listFiles()) { if (subfile.getPath().toLowerCase().endsWith(ext)) { l.add(subfile); } } if (l.size > 0) { String filename = l.get((int) (Math.random() * l.size)).getName(); m.put(file.name, filename); } } } } } } for(SkinConfig.Offset offset : property.getOffset()) { m.put(offset.name, offset); } mode = header.getSkinType().getMode(); return loadSkin(f, state, header, option, m); } public abstract S loadSkin(Path f, MainState state, SkinHeader header, IntIntMap option, ObjectMap property) throws IOException; /** * SkinTypeに対応したLR2SkinCSVLoaderを返す * @param type SkinType * @param src Skinの元解像度 * @param c コンフィグ * @return 対応するLR2SkinCSVLoader。存在しない場合はnull */ public static LR2SkinCSVLoader getSkinLoader(SkinType type, Resolution src, Config c) { switch(type) { case MUSIC_SELECT: return new LR2SelectSkinLoader(src, c); case DECIDE: return new LR2DecideSkinLoader(src, c); case PLAY_5KEYS: case PLAY_7KEYS: case PLAY_9KEYS: case PLAY_10KEYS: case PLAY_14KEYS: return new LR2PlaySkinLoader(type, src, c); case RESULT: return new LR2ResultSkinLoader(src, c); case COURSE_RESULT: return new LR2CourseResultSkinLoader(src, c); case KEY_CONFIG: return null; case SKIN_SELECT: return new LR2SkinSelectSkinLoader(src, c); } return null; } } enum CSVCommand implements LR2SkinLoader.Command<LR2SkinCSVLoader> { STARTINPUT { @Override public void execute(LR2SkinCSVLoader loader, String[] str) { loader.skin.setInput(Integer.parseInt(str[1])); } }, SCENETIME { @Override public void execute(LR2SkinCSVLoader loader, String[] str) { loader.skin.setScene(Integer.parseInt(str[1])); } }, FADEOUT { @Override public void execute(LR2SkinCSVLoader loader, String[] str) { loader.skin.setFadeout(Integer.parseInt(str[1])); } } ; }