diff --git a/src/main/java/com/pixelgamelibrary/api/Pixel.java b/src/main/java/com/pixelgamelibrary/api/Pixel.java index d4621ef..4ba5d22 100644 --- a/src/main/java/com/pixelgamelibrary/api/Pixel.java +++ b/src/main/java/com/pixelgamelibrary/api/Pixel.java @@ -28,6 +28,7 @@ import com.pixelgamelibrary.api.interfaces.Internal; import com.pixelgamelibrary.api.interfaces.Net; import com.pixelgamelibrary.api.interfaces.Utils; import com.pixelgamelibrary.api.interfaces.App; +import com.pixelgamelibrary.api.interfaces.Extension; /** * @@ -47,38 +48,46 @@ public class Pixel { //// public static App app() { - return get().app(); + return extension().getOrDefault(App.class, get().app()); } public static Graphics graphics() { - return get().graphics(); + return extension().getOrDefault(Graphics.class, get().graphics()); } public static Audio audio() { - return get().audio(); + return extension().getOrDefault(Audio.class, get().audio()); } public static Input input() { - return get().input(); + return extension().getOrDefault(Input.class, get().input()); } public static Net net() { - return get().net(); + return extension().getOrDefault(Net.class, get().net()); } public static Files files() { - return get().files(); + return extension().getOrDefault(Files.class, get().files()); } public static Utils utils() { - return get().utils(); + return extension().getOrDefault(Utils.class, get().utils()); } public static Internal internal() { - return get().internal(); + return extension().getOrDefault(Internal.class, get().internal()); } - //// + public static Extension extension() { + return get().extension(); + } + + public static T get(Class clazz) { + return get().get(clazz); + } + + //// public static void initBackend(PixelBackend pixelBackend) { if (isBackendSet()) { throw new PixelException("Pixel Backend was already set"); diff --git a/src/main/java/com/pixelgamelibrary/api/extension/ExtensionImpl.java b/src/main/java/com/pixelgamelibrary/api/extension/ExtensionImpl.java new file mode 100644 index 0000000..07585dc --- /dev/null +++ b/src/main/java/com/pixelgamelibrary/api/extension/ExtensionImpl.java @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// Pixel: Game library. +// Copyright (C) 2024 the original author or authors. +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see +// or write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +/////////////////////////////////////////////////////////////////////////////////////////////// +package com.pixelgamelibrary.api.extension; + +import com.pixelgamelibrary.api.PixelException; +import com.pixelgamelibrary.api.interfaces.Extension; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * + * @author robertvokac + */ +public class ExtensionImpl implements Extension { + + private static final ExtensionImpl INSTANCE = new ExtensionImpl(); + + public static Extension getInstance() { + return INSTANCE; + } + + public ExtensionImpl() { + + } + // Map to hold registered implementations + private final Map, Object> implementations = new HashMap<>(); + +// Implement the method for registering implementations + @Override + public void register(Class interfaceClass, T implementation) { + if(interfaceClass == Extension.class) { + throw new PixelException("Custom implementation of interface Extension cannot be registred."); + } + implementations.put(interfaceClass, implementation); + System.out.println("Registered implementation for: " + interfaceClass.getName()); + } + +// Implementation of the generic method getImplementation \ + @Override + public T get(Class clazz) { + T implementation = (T) implementations.get(clazz); + if (implementation == null) { + throw new IllegalArgumentException("No implementation registered for: " + clazz.getName()); + } + return implementation; + } + + @Override + public boolean has(Class clazz) { + return implementations.containsKey(clazz); + } + + @Override + public List> list() { + return implementations.keySet().stream().collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/pixelgamelibrary/api/interfaces/Extension.java b/src/main/java/com/pixelgamelibrary/api/interfaces/Extension.java new file mode 100644 index 0000000..a8cc2e4 --- /dev/null +++ b/src/main/java/com/pixelgamelibrary/api/interfaces/Extension.java @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////////////////////// +// Pixel: Game Library - Extension Module +// Copyright (C) 2024 the original author or authors. +// +// This program is free software: you can redistribute it and/or modify it under the terms of +// the GNU General Public License as published by the Free Software Foundation, either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with this program. +// If not, see or write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//////////////////////////////////////////////////////////////////////////////////////////////// +package com.pixelgamelibrary.api.interfaces; + +import java.util.List; + +/** + * The Extension interface allows the registration and retrieval of various + * implementations for specific interfaces. It acts as a flexible extension + * module, enabling dynamic modularization and adding extensibility to the + * Pixel Game Library. + * + * This interface provides generic methods to register, retrieve, and check + * the availability of registered implementations, offering a loosely coupled + * and highly flexible way to extend the game library. + * + * @author robertvokac + */ +public interface Extension { + + /** + * Registers an implementation for a given interface class. + * + * This method allows you to register an implementation for a specific + * interface, enabling the extension mechanism to return the appropriate + * implementation when requested. + * + * @param the type of the interface to be registered + * @param interfaceClass the Class object of the interface to be implemented + * @param implementation the instance of the implementation that corresponds to the interface + */ + void register(Class interfaceClass, T implementation); + + /** + * Retrieves the registered implementation for a given interface. + * + * This method returns the implementation instance that was previously + * registered for the provided interface class. + * + * @param the type of the interface + * @param clazz the Class object of the interface for which the implementation is requested + * @return the registered implementation of the interface, or null if no implementation is registered + */ + T get(Class clazz); + + default T getOrDefault(Class clazz, T defaultInstance) { + if(has(clazz)) { + return get(clazz); + } else { + return defaultInstance; + } + } + + /** + * Checks if an implementation is registered for a specific interface class. + * + * This method verifies whether there is an implementation registered for + * the given interface class. + * + * @param the type of the interface + * @param clazz the Class object of the interface to be checked + * @return true if an implementation is registered, false otherwise + */ + boolean has(Class clazz); + + /** + * Lists all the registered interface classes. + * + * This method provides a list of all the interface classes for which + * implementations have been registered. It can be useful for debugging or + * introspection purposes. + * + * @return a List of Class objects representing the registered interfaces + */ + List> list(); +} diff --git a/src/main/java/com/pixelgamelibrary/api/interfaces/PixelBackend.java b/src/main/java/com/pixelgamelibrary/api/interfaces/PixelBackend.java index 8cd30de..098dcbe 100644 --- a/src/main/java/com/pixelgamelibrary/api/interfaces/PixelBackend.java +++ b/src/main/java/com/pixelgamelibrary/api/interfaces/PixelBackend.java @@ -19,6 +19,9 @@ /////////////////////////////////////////////////////////////////////////////////////////////// package com.pixelgamelibrary.api.interfaces; +import com.pixelgamelibrary.api.PixelException; +import com.pixelgamelibrary.api.extension.ExtensionImpl; + /** * * @author robertvokac @@ -29,9 +32,29 @@ public interface PixelBackend { Graphics graphics(); Audio audio(); Input input(); + // Net net(); Files files(); Utils utils(); Internal internal(); + // + default Extension extension() { + return ExtensionImpl.getInstance(); + } + + default T get(Class clazz) { + if(clazz.equals(App.class)) {return (T) app();} + if(clazz.equals(Graphics.class)) {return (T) graphics();} + if(clazz.equals(Audio.class)) {return (T) audio();} + if(clazz.equals(Input.class)) {return (T) input();} + // + if(clazz.equals(Net.class)) {return (T) net();} + if(clazz.equals(Files.class)) {return (T) files();} + if(clazz.equals(Utils.class)) {return (T) utils();} + if(clazz.equals(Internal.class)) {return (T) internal();} + // + if(clazz.equals(Extension.class)) {return (T) extension();} + throw new PixelException("Unsupported interface: " + clazz.getName()); + } }